Compare commits

...
Author SHA1 Message Date
Landon Wills 0af70a1433 Update tinkaton animation, support changes in fov 2025-04-17 23:27:54 -04:00
Landon Wills 268e7c4afc Merge branch 'refs/heads/main' into camera-test 2025-04-17 06:39:25 -04:00
Landon Wills 070d6f9529 Add ceruledge test animation 2025-04-17 06:38:56 -04:00
Landon Wills 8420dd6fe3 Embed camera into model locator. Much cleaner solution 2025-04-17 05:20:26 -04:00
Landon Wills 24ee96a85d Allow for either provided animation to played 2025-04-17 01:50:48 -04:00
Landon Wills 32ff4ee609 Use tandemaus animation for example 2025-04-17 01:03:42 -04:00
Landon Wills 7a61ce1a94 Make tinkaton use primary animation 2025-04-17 01:02:48 -04:00
Landon Wills 46f43345f2 Things and stuff 2025-04-16 23:18:38 -04:00
Polymeta baf3cd5f30 Merge branch 'moon-ball-fix-🌕🌒🌓🌔🌑🌘🌗🌖' into 'main'
Fix the messed up Moon Phase code for the Moon Ball catch rate

See merge request cable-mc/cobblemon!1605
2025-04-16 17:16:36 +00:00
Plastered_Crab 2327f1aa2c Add this to make Polymeta happy 2025-04-16 09:46:11 -07:00
plastered_crab 62036c0ac6 Fix the messed up Moon Phase code for the Moon Ball catch rate 2025-04-16 07:57:00 -07:00
Landon Wills ad438bfbcd Merge branch 'refs/heads/main' into stadium-block-gert
# Conflicts:
#	common/src/main/java/com/cobblemon/mod/common/mixin/client/CameraMixin.java
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonNetwork.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/data/CobblemonDataProvider.kt
2025-04-16 03:23:04 -04:00
Landon 2db494ff5e Merge branch 'Dex-Species-Forms' into 'main'
Update English Lang with official values and preliminary species form support for the dex

See merge request cable-mc/cobblemon!1454
2025-04-16 04:43:43 +00:00
Konoha 7fe1415551 Clean InfoWidget form parsing. 2025-04-15 23:24:56 -04:00
Konoha ca4d4ed3be Re-Run Lang Key Scrape & Changelog 2025-04-15 09:02:29 -04:00
Konoha 700227be41 Merge branch 'main' into Dex-Species-Forms
# Conflicts:
#	common/src/main/resources/assets/cobblemon/lang/en_us.json
2025-04-15 08:39:33 -04:00
Konoha 985a4f65dc Re-Run Lang Key Scrape & Changelog 2025-04-15 08:16:41 -04:00
Konoha e117100e34 Re-Run Lang Key Scrape & Changelog 2025-04-15 08:06:10 -04:00
Konoha 93ea13fa4d Merge branch 'main' into Dex-Species-Forms 2025-04-15 07:57:01 -04:00
Gertimoshka 5bc056d28e Breaking my head working on this, but steady progress finalizing the camera system itself 2025-04-15 11:54:29 +03:00
Polymeta cd14881d17 Merge branch 'immersive-tweaks' into 'main'
Foods and Recipes

See merge request cable-mc/cobblemon!1554
2025-04-14 20:45:41 +00:00
dhi_holoandPolymeta 1393cc3ef3 Foods and Recipes 2025-04-14 20:45:40 +00:00
Konoha 23ebd0573a Merge branch 'implement_pokemon' into Dex-Species-Forms
# Conflicts:
#	common/src/main/resources/assets/cobblemon/lang/en_us.json
2025-04-14 08:05:18 -04:00
Polymeta 6447c2e2eb Merge branch 'per-world-gamerule-support' into 'main'
Add per-level gamerule support for doPokemonSpawning

See merge request cable-mc/cobblemon!1593
2025-04-14 11:32:54 +00:00
BlackBeltPanda 039a18a2bf Update CHANGELOG.md 2025-04-14 04:46:06 -04:00
FrankTheFarmer 71736341f0 Merge branch 'main' into implement_pokemon 2025-04-14 13:55:12 +10:00
Landon bb6e5607f1 Merge branch 'stop-head-pitch' into 'main'
Make head moving actually stop this time.

See merge request cable-mc/cobblemon!1596
2025-04-13 04:55:00 +00:00
Landon 4603f5ac7a Merge branch 'riding-animation-01' into 'main'
Riding dynamic animation, riding fixes, and controller tweaks

See merge request cable-mc/cobblemon!1599
2025-04-12 23:59:31 +00:00
Jackson BowesandLandon c683294227 Riding dynamic animation, riding fixes, and controller tweaks 2025-04-12 23:59:31 +00:00
JPAK f29c2343e6 Merge remote-tracking branch 'origin/stop-head-pitch' into stop-head-pitch 2025-04-12 16:41:40 -05:00
JPAK 3a2da5a87d Make head moving actually stop this time. 2025-04-12 16:41:13 -05:00
QriviateA 27d1de8e4e Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-04-12 17:14:04 +01:00
QriviateA 8af62f800b Updated changelog 2025-04-12 01:27:10 +01:00
QriviateA a50da47a8e Updated Kangaskhan model + anims 2025-04-12 01:26:47 +01:00
QriviateA f690781b0d Updated Cinderace model + anims 2025-04-12 01:26:16 +01:00
FrankTheFarmer 6a7fc67ae1 Merge branch 'main' into implement_pokemon 2025-04-12 08:10:08 +10:00
JPAK 4722defec2 Make head moving actually stop this time. 2025-04-10 13:14:32 -05:00
FrankTheFarmer 7b7acb97d1 Changelog 2025-04-10 23:05:56 +10:00
FrankTheFarmer 53af92f254 Implemented Metagross with locators for testing 2025-04-10 23:04:07 +10:00
FrankTheFarmer 91bce4b153 Merge branch 'main' into implement_pokemon 2025-04-10 22:32:31 +10:00
BlackBeltPanda 511130d353 Remove redundant check for player UUID in spawnersForPlayers and early return in registerPlayerSpawner 2025-04-10 05:42:10 -04:00
BlackBeltPanda 476c3e54f1 Return early in CobbledWorldSpawnerManager#onDimensionChange when DO_POKEMON_SPAWNING gamerule is equal in origin and destination levels 2025-04-10 05:40:13 -04:00
FrankTheFarmer 4bfe8b808c Implemented Magnezone with locators for testing 2025-04-10 16:36:21 +10:00
FrankTheFarmer 8db943d2a9 Merge branch 'main' into implement_pokemon 2025-04-10 16:34:54 +10:00
FrankTheFarmer fdff6ecfa5 Implemented Magnezone with locators for testing 2025-04-10 16:33:51 +10:00
BlackBeltPanda 2eb698969d Add onDimensionChange method to CobbledWorldSpawnerManager 2025-04-10 01:52:12 -04:00
BlackBeltPanda bba60f0098 Check DO_POKEMON_SPAWNING gamerule for the correct Level in SpawnerManager#onServerTick and CobbledWorldSpawnerManager#onPLayerLogin 2025-04-10 01:50:33 -04:00
BlackBeltPanda 8ee2c95853 Add unregisterPlayerSpawner and registerPlayerSpawner methods to CobbledWorldSpawnerManager 2025-04-10 01:45:43 -04:00
BlackBeltPanda 77db2ce17a Add origin and destination ServerLevel properties to ChangeDimensionEvent 2025-04-10 01:43:59 -04:00
FrankTheFarmer ff5ea6fa21 Merge branch 'main' into implement_pokemon 2025-04-08 19:42:22 +10:00
FrankTheFarmer 4820d78416 Implemented Jolteon's item holding animation 2025-04-08 19:05:35 +10:00
FrankTheFarmer 2f417e953c Added placeholder cry to the eeveelution animations 2025-04-08 18:38:39 +10:00
FrankTheFarmer 8fde0ed4f6 Added rootbone and cry back to the eeveelution posers 2025-04-08 18:38:08 +10:00
FrankTheFarmer 6715874a8f Merge branch 'main' into implement_pokemon 2025-04-08 16:00:52 +10:00
RedGenesectNinja 31f88a1f68 Implemented Druddigon 2025-04-08 00:37:09 -05:00
FrankTheFarmer f80aa2769a Restored Treecko line cries 2025-04-08 10:55:39 +10:00
FrankTheFarmer 20aa4d43b8 Delphox wand animation tweaks 2025-04-08 09:19:10 +10:00
FrankTheFarmer 9bec3e088f Changelog moment 2025-04-08 08:42:49 +10:00
FrankTheFarmer 5b4dbe1957 Imported old placeholder walk and cry for Braixen and Delphox 2025-04-08 08:36:19 +10:00
FrankTheFarmer 48f248d481 Fixed a crash caused by cosmetic remodels for Braixen and Delphox. 2025-04-08 08:36:00 +10:00
FrankTheFarmer d726c4d0ed Merge branch 'main' into implement_pokemon
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/repository/VaryingModelRepository.kt
2025-04-08 08:19:12 +10:00
FrankTheFarmer c9c421ba2a Fixed Sneasler model issues from previous update for cosmetic basket. 2025-04-07 21:00:12 +10:00
FrankTheFarmer 2436a8ddcc Fixed Tropius typo in changelog 2025-04-07 20:04:13 +10:00
FrankTheFarmer 3364944c26 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-04-07 19:57:12 +10:00
FrankTheFarmer 9e6a6eabc7 Fixed the wrong type of Crocs mentioned in the changelog 2025-04-07 19:55:57 +10:00
FrankTheFarmer 78def7318e Treecko my beloved. Gave json poser and fixed t-pose 2025-04-07 19:55:09 +10:00
FrankTheFarmer fdf062bd4c oops, fixed dex number for grovyle poser 2025-04-07 19:44:37 +10:00
FrankTheFarmer ef5a682adb Fixed stick related Grovyle crash and gave it a JSON poser 2025-04-07 19:41:11 +10:00
Polymeta f76d28d29e updated changelog 2025-04-07 09:35:20 +00:00
FrankTheFarmer 9c70aad64d Fixed stick related Sceptile crash and gave it a JSON poser 2025-04-07 19:17:56 +10:00
FrankTheFarmer 25de1ad180 Merge branch 'main' into implement_pokemon 2025-04-07 15:13:02 +10:00
FrankTheFarmer f967d1ec11 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-04-07 15:12:10 +10:00
FrankTheFarmer efd0497de1 Fixed Garchomp using battle idle in its portrait and profile 2025-04-07 15:00:47 +10:00
Kenji_64 b30c0a4a9a Adjusted Nosepass' walk speed. (Thanks Lennie and Frank!) 2025-04-06 22:21:25 +02:00
Kenji_64 c99b26a44b Added animations to Nosepass and Probopass. Made new JSON posers and replaced the Kotlin ones (thanks Lennie!) 2025-04-06 21:06:37 +02:00
FrankTheFarmer b19bc1e4c7 updated changelog 2025-04-06 21:21:37 +10:00
FrankTheFarmer bc5ffda1a5 Expedited crobat with locators 2025-04-06 21:19:09 +10:00
FrankTheFarmer 491d6c9fd6 Expedited salamence with locators 2025-04-06 21:19:01 +10:00
FrankTheFarmer ccc6ad77a5 Garchomp and perchance the craziest poser that ever lived 2025-04-06 19:47:02 +10:00
FrankTheFarmer 00fd9d1278 oopsies forgot portrait and profile data on honchkrow 2025-04-06 19:47:02 +10:00
FrankTheFarmer 01464f8b71 Expediting more models for reasons the government will not allow me to explain 2025-04-06 19:47:01 +10:00
FrankTheFarmer d91fe0b876 Merge branch 'main' into implement_pokemon 2025-04-06 18:56:00 +10:00
Gertimoshka 3033adcc2f IT MOVES 2025-04-05 11:55:07 +03:00
Gertimoshka 252634bfde Setup the code that will handle the camera data and apply it 2025-04-05 08:04:24 +03:00
FrankTheFarmer 3f6faf7796 Merge branch 'main' into implement_pokemon 2025-04-05 09:24:40 +10:00
Sterrezo d5efdeee68 More adjustments to the cry checker script 2025-04-04 19:06:22 +02:00
queao 57f446260c just gonna drop these in here (added remodels for eevee and all eeveelutions) 2025-04-04 15:53:56 +10:00
Kenji_64 d4cf44f8f0 Removed the old Three Segment Aspect 2025-04-03 18:54:29 +02:00
Kenji_64 a074ebbcce It has been du-dune: Implemented Dunsparce + Dudunsparce (2 & 3 Segment Form) 2025-04-03 18:54:00 +02:00
queao 6578ed55e3 whoopsies 2025-04-03 16:12:39 +10:00
Tyzillion f567ceadd8 Implemented Cosmetics for Gurdurr, Conkeldurr, Squirtle Line, Sneasler, Sandle line, Treecko line, Braixen, Delphox, and Dragonite.
Removed Shulker aspect and replaced it with cosmetic_item-shulker_shell.
Shulker shell Forretress is now a cosmetic rather than a special evo.
2025-04-02 18:03:11 -04:00
FrankTheFarmer 5de92f78c6 Changelog 👨‍🌾🔫🐲 2025-04-02 22:50:23 +10:00
FrankTheFarmer a2402f78e7 Added Sandaconda 🐍🐍🐍 2025-04-02 22:47:37 +10:00
FrankTheFarmer 1ad6d63137 Added Silicobra 🪱 2025-04-02 22:45:54 +10:00
FrankTheFarmer 39d417c651 Added Bronzong 👁🔔👁 2025-04-02 22:44:14 +10:00
FrankTheFarmer ce1bf9f4f2 Added Bronzor 🔷 2025-04-02 22:43:41 +10:00
FrankTheFarmer a6136906f8 Added Musharna 💤🐖 2025-04-02 22:42:44 +10:00
FrankTheFarmer 37a99b528e Added Munna 🐖 2025-04-02 22:40:46 +10:00
FrankTheFarmer 048b237302 Added Zebstrika ⚡🦓⚡ 2025-04-02 22:38:17 +10:00
FrankTheFarmer 131773f9c8 Added Blitzle ⚡🦓 2025-04-02 22:37:56 +10:00
FrankTheFarmer 22e55b7e77 Added Arboliva 🌵 2025-04-02 22:36:29 +10:00
FrankTheFarmer 6c288f9cc8 Added Dolliv 🫒🦵 2025-04-02 22:31:52 +10:00
FrankTheFarmer b5e86a9460 Added Smoliv 🫒 2025-04-02 22:30:53 +10:00
FrankTheFarmer f199e7c1c0 Added Froslass ✨👩‍🦳❄ 2025-04-02 22:29:05 +10:00
FrankTheFarmer 4161d96707 Added Glalie ⚪ 2025-04-02 22:27:35 +10:00
FrankTheFarmer 59927dd701 Added Snorunt 📐 2025-04-02 22:26:58 +10:00
FrankTheFarmer 220d8ddc0f Added Grumpig 🐖🔮 2025-04-02 22:25:53 +10:00
FrankTheFarmer 0dd143e67e Added Spoink 🔮🐷 2025-04-02 22:24:57 +10:00
FrankTheFarmer d83eb62821 Added Garbodor 🤮 2025-04-02 22:22:52 +10:00
FrankTheFarmer a716fda023 Added Trubbish 🤢 2025-04-02 22:22:25 +10:00
FrankTheFarmer d14aad787c Added Orthworm 🪱♥❓🥺 2025-04-02 22:19:01 +10:00
FrankTheFarmer 2eb7b60dd1 Added Drampa 👴🐉🔥🏠 2025-04-02 22:11:41 +10:00
FrankTheFarmer d79ffc631b Merge branch 'main' into implement_pokemon 2025-04-02 08:41:27 +10:00
Gertimoshka 0f38c6b00e Setup Data Handling and Syncing for Stadium Cameras 2025-04-01 15:27:22 +03:00
FrankTheFarmer 7cd1870f23 Merge branch 'main' into implement_pokemon 2025-03-31 07:42:53 +10:00
Gertimoshka f711f748a8 A lot of Stadium Camera Data for the Data Gods before implementation 2025-03-29 10:27:34 +02:00
Sterrezo 716d1b848e Fixed and renamed cries for Galarian Ponyta, Galarian Rapidash and Alolan Raichu 2025-03-26 16:19:26 +01:00
Sterrezo 4878fc517d Updated and cleaned up the cry checker script 2025-03-26 16:00:57 +01:00
Sterrezo 4d9d543110 STOP BREAKING THE SPREADSHEET
fixed script
2025-03-26 14:26:15 +01:00
FrankTheFarmer 718a9b922b Merge branch 'main' into implement_pokemon 2025-03-26 08:28:53 +10:00
GenotypeXD-Dev e2a152aeb3 Model Fixes didnt push 2025-03-24 19:34:11 -06:00
GenotypeXD-Dev 3e21226b27 Implemented Hawlucha + fixed z fighting on Noibat and scaled down to 0.6 2025-03-24 19:30:16 -06:00
queao c46c5b806c IT'S TIIIIIIIIIIME (implemented noibat and noivern - implementation work done by genotype) 2025-03-24 18:49:07 +10:00
FrankTheFarmer 3c37d93046 Merge branch 'main' into implement_pokemon 2025-03-24 16:40:53 +10:00
Gertimoshka c2fb914e08 Working on Networking for Stadium 2025-03-22 23:33:35 +02:00
Gertimoshka 7947e19337 Fixed Errors with Mergin Main into branch 2025-03-21 21:56:49 +02:00
Gertimoshka 5bde172731 Detached the Camera from the player 2025-03-21 21:43:59 +02:00
Gertimoshka 496e04a779 Merging Main into stadium-block-gert 2025-03-21 14:50:22 +02:00
Gertimoshka ff4192b43c Preparing to handle starting Stadium Battles 2025-03-21 14:47:27 +02:00
Gertimoshka 415591a443 Stadium Block now can innitate a 1v1 battle 2025-03-21 14:47:26 +02:00
Gertimoshka efb1eaf3e1 Setup to prepare to develop Stadium Block Functionality 2025-03-21 14:47:26 +02:00
Plastered_CrabandGertimoshka 7ebd2bdb94 Render Rotom drone camera to start orbiting around + try to avoid collisions using raycast point cloud 2025-03-21 14:47:24 +02:00
FlarkinaterandGertimoshka e07579bf0a Fix drone animation 2025-03-21 14:47:23 +02:00
FlarkinaterandGertimoshka 0695117549 Revert debug change 2025-03-21 14:47:22 +02:00
FlarkinaterandGertimoshka d6cd04e2a4 Attempt to debug the animation issue 2025-03-21 14:47:21 +02:00
FlarkinaterandGertimoshka 8240cd10e2 Attempt to make the drone animated (WIP) 2025-03-21 14:47:19 +02:00
FlarkinaterandGertimoshka 2a1e749787 Refactor - move most drone assets into bedrock/drone 2025-03-21 14:47:18 +02:00
FlarkinaterandGertimoshka 6d9daf692d Fix upside-down drone 2025-03-21 14:47:17 +02:00
FlarkinaterandGertimoshka 1f7df20e77 Render the drone in-game 2025-03-21 14:47:16 +02:00
FlarkinaterandGertimoshka 02a4b91778 Add Rotom drone model/texture/animation placeholders 2025-03-21 14:47:15 +02:00
FlarkinaterandGertimoshka a37da4d4f2 Remove placeholder model, we'll just use some "dev art" for now 2025-03-21 14:47:14 +02:00
FlarkinaterandGertimoshka 66817b5e9b Update deprecated methods, imports, and formatting 2025-03-21 14:47:10 +02:00
FlarkinaterandGertimoshka fd54e3a7e0 Rebase old stadium camera test branch 2025-03-21 14:47:08 +02:00
Gertimoshka 79f2b67bf9 Preparing to send client reqired info about Stadium Battle 2025-03-21 14:44:34 +02:00
Gertimoshka 2352dae6e0 Preparing to handle starting Stadium Battles 2025-03-20 18:35:46 +02:00
Gertimoshka 9ec100f9ea Stadium Block now can innitate a 1v1 battle 2025-03-20 12:36:12 +02:00
FrankTheFarmer 7b2790de50 Changelog setup for 1.7 implementation stuff 2025-03-18 09:20:30 +10:00
FrankTheFarmer 7f2bb84c85 Merge branch 'main' into implement_pokemon 2025-03-18 09:12:06 +10:00
Gertimoshka 17c524ab9e Setup to prepare to develop Stadium Block Functionality 2025-03-17 22:30:28 +02:00
FrankTheFarmer 331e1371d4 Illegal imports of Dragonite and Gyarados models with locators for testing 2025-03-16 09:42:56 +10:00
FrankTheFarmer bdd57ba1a4 Merge branch 'main' into implement_pokemon 2025-03-16 08:53:37 +10:00
FrankTheFarmer 670e7e9ca1 Merge branch 'main' into implement_pokemon 2025-03-13 13:55:26 +10:00
FrankTheFarmer 3ae349aea5 Merge branch 'main' into implement_pokemon 2025-03-06 18:28:14 +10:00
FrankTheFarmer 13650f98f9 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-03-05 14:23:08 +10:00
FrankTheFarmer d3379557fd 2 more Gen 5 monkeys jumping on the bed 2025-03-05 14:22:28 +10:00
FrankTheFarmer 143c2683fe Added placeholder animations to Pansage and Simisage 2025-03-05 14:21:54 +10:00
FrankTheFarmer 72d64d36e5 Changed panpour scale and hitbox size to match that of the other monkeys 2025-03-05 14:21:17 +10:00
Wi2tert c0b52c38e3 "implemented": Panpour、Simipour 💧🐒 2025-03-05 12:11:22 +08:00
FrankTheFarmer 12a0ee309e Merge branch 'main' into implement_pokemon 2025-03-05 08:01:14 +10:00
RedGenesectNinja 824e37effd Implemented Pansage and Simisage 2025-03-03 23:12:27 -06:00
Plastered_Crab 86d48df9fe Render Rotom drone camera to start orbiting around + try to avoid collisions using raycast point cloud 2025-02-28 16:59:03 -08:00
Flarkinater 3401ba9cbb Fix drone animation 2025-02-15 21:48:29 -05:00
Flarkinater dac9ccb461 Revert debug change 2025-02-15 21:47:59 -05:00
Flarkinater 191a62f693 Attempt to debug the animation issue 2025-02-15 16:50:52 -05:00
Flarkinater d8d410e539 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into stadium-block 2025-02-15 15:37:37 -05:00
Flarkinater b7c6e1ea77 Attempt to make the drone animated (WIP) 2025-02-15 15:35:48 -05:00
Kenji_64 975cdf050f Fixed Charcadet's cry sound event not being there and head pivot 2025-02-15 15:34:34 +01:00
Flarkinater 186812d6fd Refactor - move most drone assets into bedrock/drone 2025-02-14 12:23:27 -05:00
Flarkinater 1c0bdc766a Fix upside-down drone 2025-02-12 14:55:41 -05:00
Flarkinater c697bcd2e9 Render the drone in-game 2025-02-12 01:17:42 -05:00
Flarkinater 9d6ff01d80 Add Rotom drone model/texture/animation placeholders 2025-02-10 20:20:24 -05:00
Flarkinater 1691853a19 Remove placeholder model, we'll just use some "dev art" for now 2025-02-10 20:20:12 -05:00
Flarkinater 4e9a4e1e5a Update deprecated methods, imports, and formatting 2025-02-10 20:20:03 -05:00
Flarkinater 6450255a0b Rebase old stadium camera test branch 2025-02-10 20:19:13 -05:00
Konoha 8fe2042127 Merge Basculin game evolutions 2025-02-02 08:17:05 -05:00
Konoha 538ad883ab Correct Spewpa evo tag reference in evolution to tag format 2025-02-02 08:02:49 -05:00
Konoha 136cb86492 Correct the consumption of held items on non-applicable item evolutions 2025-02-01 08:22:12 -05:00
Konoha e4eb1251d1 Fix Goomy & Bergmite branch evolutions, branching stone anticondition conflict. 2025-02-01 07:51:39 -05:00
Valerie Rice 1bc83d9045 poison frog man (only the little one) 2025-01-28 16:22:21 +10:00
Konoha 98775ffc1e Merge branch 'main' into Dex-Species-Forms
# Conflicts:
#	common/src/main/resources/assets/cobblemon/lang/en_us.json
2025-01-27 09:26:48 -05:00
Konoha bbeb3d45f0 Merge branch 'implement_pokemon' into Dex-Species-Forms 2025-01-21 11:37:28 -05:00
Konoha 8fd854f7f7 Merge branch 'main' into Dex-Species-Forms 2025-01-18 16:48:07 -05:00
Konoha f449cf27c5 Merge branch 'implement_pokemon' into Dex-Species-Forms 2025-01-18 10:59:31 -05:00
Konoha bf5fd5eed8 Merge remote-tracking branch 'origin/main' 2025-01-03 19:19:26 -05:00
Konoha facead5f0b Preliminary species form support for Pokedex 2025-01-03 19:12:31 -05:00
250 changed files with 35582 additions and 8809 deletions
+20
View File
@@ -17,6 +17,8 @@
- Added cosmetics for Gurdurr, Conkeldurr, Squirtle Line, Sneasler, Sandle line, Treecko line, Braixen, Delphox, and Dragonite.
- Added `/transformmodelpart (position|rotation|scale) <modelPart> <transform: x y z>` command that can add transformations to a pokemon's model part.
- The player executing the command must be facing the target pokemon entity. Transformations are not persistent and will revert when resources are reloaded.
- Added lang keys for all moves and abilities up to Generation 9.
- Fixed Moon Ball moon phase logic to actually work correctly
### Pokémon Added
@@ -76,6 +78,8 @@
- Sneasler
- Braixen
- Delphox
- Cinderace
- Kangaskhan
### Model updates for the following Pokémon
- Gyarados
@@ -97,18 +101,32 @@
- Pidgeot
- Nosepass
- Probopass
- Kangaskhan
- Cinderace
- Magnezone
- Metagross
- Added Syrupy Apples.
### Changes
- Renamed `chargeGainedPerTick` config to `secondsToChargeHealingMachine`.
- Made Blocks of Gold count as Big Nuggets when held by a Pokémon (for Fling functionality)
- Players can now eat Sweet and Tart Apples, Whipped Dreams, and the Alcremie Sweets.
- Updated Sweet and Tart Apple sprites
- Updated the following recipes: Air Balloon, Assault Vest, Binding Band, Black Belt, Blunder Policy, Choice Band, Choice Scarf, Cleanse Tag, Covert Cloak, Destiny Knot, Eject Button, Expert Belt, Focus Band, Focus Sash, Magnet, Metronome, Muscle Band, Power Anklet, Power Band, Power Belt, Power Bracer, Power Lens, Power Weight, Protective Pads, Protein, Punching Glove, Reaper Cloth, Rocky Helmet, Room Service, Sachet, Safety Goggles, Silk Scarf, Spell Tag, Utility Umbrella, Weakness Policy, Zinc
- Added alternate ingredient options to the following recipes: Cell Battery, Charcoal Stick, Dragon Fang, Miracle Seed, Mystic Water, Never Melt Ice, Twisted Spoon, Damp Rock, Heat Rock, Icy Rock, Smooth Rock
- Grouped together some recipes within the Recipe Book. Groups include: the seven basic Poké Balls, the seven basic Ancient Poké Balls, Gilded Chests, Pokedexes, and the Weather Rocks.
- Updated some item tags to better integrate behaviours between Cobblemon, Vanilla Minecraft, and other mods
- Removed Cooked Meat, Raw Meat, Protein Ingredients, and Zinc Ingredients, the first two are now using `c` namespace tags, the latter have better integrated use of tags within their recipes which removes need for custom tags.
- Added our seeds tag into `#c:seeds`, which is now made use of for the Miracle Seed recipe.
- Tweaked the Natural Materials Vanilla file to fit with the changes to tags
- Substantially optimised spawning checks mainly by front-loading biome filtering.
- When using the `cobblemon` or `generation_9` capture calculators a critical capture with a single shake will always play for successful captures when you've already registered the Pokémon as caught in your Pokédex.
- Improved the performance of saving Pokédex and player data.
- Pokémon hitbox now scales with entity attribute `generic.scale`.
- Removed Shulker aspect and replaced it with cosmetic_item-shulker_shell.
- Shulker shell Forretress is now a cosmetic rather than a special evo and thus all shulker Forretress will revert back to normal until a shulker shell is put in their cosmetic slot.
- Updated `doPokemonSpawning` gamerule to support per-dimension configurations.
- The Pokedex now displays a form name of a "normal" Pokémon for when the base form is still a named form.
### Fixes
- Fixed Particles sometimes facing the wrong direction (looking at you, Swords Dance)
@@ -137,6 +155,7 @@
- Fixed Pokémon marked as silent still playing shiny sounds and effects.
- Fixed an issue with newer versions of Fabric API where underground Pokémon were spawning in The End.
- Fixed spawning not working well when you're at high points surrounded by lower altitude spawning areas, such as flying.
- Fixed certain Pokémon with forms not having appropriate stock Pokédex entries.
### Developer
- A finished battle now has winners and losers set inside of `PokemonBattle` instead of them always being empty.
@@ -173,6 +192,7 @@
- Added `pokemon` as an available Molang function for the `battleActor` functions.
- Fixed `heldItem` property inside spawn files not working and causing crashes
- Fixed `spawn_bedrock_particles` MoLang causing crashes when used in a server environment
- The Pokédex form lang key definition now follows `cobblemon.ui.pokedex.info.form.{species}-{formname}` instead of `cobblemon.ui.pokedex.info.form.{formname}`.
## [1.6.1 (January 26th, 2025)](#1-6-1)
@@ -8,11 +8,24 @@
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.api.orientation.OrientationController;
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker;
import com.cobblemon.mod.common.stadium.StadiumClientManager;
import com.cobblemon.mod.common.util.CameraExtensionsKt;
import net.minecraft.client.Camera;
import net.minecraft.client.DeltaTracker;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.Vec3;
import org.joml.Matrix4f;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@@ -20,6 +33,17 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(GameRenderer.class)
public class GameRendererMixin {
@Shadow @Final Minecraft minecraft;
@Shadow float renderDistance;
@Shadow @Final private LightTexture lightTexture;
@Shadow private boolean renderHand;
@Shadow private double getFov(Camera activeRenderInfo, float partialTicks, boolean useFOVSetting) { return 0.0; }
@Shadow public void resetProjectionMatrix(Matrix4f matrix) {}
@Shadow public Matrix4f getProjectionMatrix(double fov) { return new Matrix4f(); }
@Shadow private void renderItemInHand(Camera camera, float partialTick, Matrix4f projectionMatrix) {}
@Shadow public void pick(float partialTicks) {}
@Unique
long lastTime = -1;
@@ -42,4 +66,54 @@ public class GameRendererMixin {
lastTime = newTime;
}
@Inject(method = "renderLevel", at = @At(value = "HEAD"), cancellable = true)
public void renderLevel(DeltaTracker deltaTracker, CallbackInfo ci) {
if (StadiumClientManager.INSTANCE.shouldUseStadiumCamera()) {
float f = deltaTracker.getGameTimeDeltaPartialTick(true);
this.lightTexture.updateLightTexture(f);
if (this.minecraft.getCameraEntity() == null) {
this.minecraft.setCameraEntity(this.minecraft.player);
}
this.minecraft.getProfiler().push("camera");
Camera stadiumCamera = new Camera();
Entity entity = (Entity) this.minecraft.player;
stadiumCamera.setup(this.minecraft.level, entity, false, false, 1.0F);
//adjust camera
StadiumClientManager.INSTANCE.updateCameraData(f);
var position = StadiumClientManager.INSTANCE.getCameraPosition();
stadiumCamera.setPosition(position);
Quaternionf rotation = StadiumClientManager.INSTANCE.getCameraRotation();
var forwardVector = rotation.transform(Camera.FORWARDS, new Vector3f());
var upVector = rotation.transform(Camera.UP, new Vector3f());
var leftVector = rotation.transform(Camera.LEFT, new Vector3f());
stadiumCamera.rotation.set(rotation);
stadiumCamera.xRot = (float)Mth.wrapDegrees(-Math.toDegrees(Math.asin(forwardVector.y)));
stadiumCamera.yRot = Mth.wrapDegrees((float)-Math.toDegrees(Camera.FORWARDS.angleSigned(forwardVector, Camera.UP)) + 180);
stadiumCamera.forwards.set(forwardVector);
stadiumCamera.up.set(upVector);
stadiumCamera.left.set(leftVector);
this.renderDistance = (float)(this.minecraft.options.getEffectiveRenderDistance() * 16);
double d = this.getFov(stadiumCamera, f, true);
Matrix4f matrix4f = this.getProjectionMatrix(d);
this.resetProjectionMatrix(matrix4f);
Quaternionf quaternionf = stadiumCamera.rotation().conjugate(new Quaternionf());
Matrix4f matrix4f2 = (new Matrix4f()).rotation(quaternionf);
this.minecraft.levelRenderer.prepareCullFrustum(stadiumCamera.getPosition(), matrix4f2, this.getProjectionMatrix(Math.max(d, (double)(Integer)this.minecraft.options.fov().get())));
this.minecraft.levelRenderer.renderLevel(deltaTracker, false, stadiumCamera, (GameRenderer) (Object) this, this.lightTexture, matrix4f2, matrix4f);
this.minecraft.getProfiler().pop();
ci.cancel();
}
}
@Inject(method = "tick", at = @At(value = "TAIL"))
public void tick(CallbackInfo ci) {
// StadiumClientManager.INSTANCE.tickCameraManager();
}
}
@@ -59,8 +59,21 @@ public class HumanoidModelMixin {
}
Entity vehicle = entity.getVehicle();
if (vehicle instanceof PokemonEntity && entity instanceof AbstractClientPlayer) {
MountedPlayerRenderer.INSTANCE.animate((PokemonEntity) vehicle, (AbstractClientPlayer) entity, relevantPartsByName, netHeadYaw, headPitch, ageInTicks, limbSwing, limbSwingAmount);
if (vehicle instanceof PokemonEntity pokemonEntity && entity instanceof AbstractClientPlayer) {
var shouldRotatePlayerHead = pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
return behaviour.shouldRotatePlayerHead(settings, state, pokemonEntity);
});
if (!shouldRotatePlayerHead) {
netHeadYaw = 0f;
headPitch = 0f;
if (this.head != null) {
this.head.yRot = 0f;
this.head.xRot = 0f;
}
}
MountedPlayerRenderer.INSTANCE.animate(pokemonEntity, (AbstractClientPlayer) entity, relevantPartsByName, netHeadYaw, headPitch, ageInTicks, limbSwing, limbSwingAmount);
}
}
}
@@ -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.client;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import net.minecraft.client.model.PlayerModel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(PlayerModel.class)
public class PlayerModelMixin {
@Inject(method = "setupAnim(Lnet/minecraft/world/entity/LivingEntity;FFFFF)V", at = @At(value = "HEAD"))
private void cobblemon$setHeadRotation(LivingEntity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch, CallbackInfo ci) {
if (!(entity instanceof Player)) return;
Entity vehicle = entity.getVehicle();
if (!(vehicle instanceof PokemonEntity pokemonEntity)) return;
var shouldRotatePlayerHead = pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
return behaviour.shouldRotatePlayerHead(settings, state, pokemonEntity);
});
if (shouldRotatePlayerHead) return;
netHeadYaw = 0f;
headPitch = 0f;
}
}
@@ -36,6 +36,9 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
@JvmField
val PC: BlockEntityType<PCBlockEntity> = this.create("pc", BlockEntityType.Builder.of(::PCBlockEntity, CobblemonBlocks.PC).build(null))
@JvmField
val STADIUM: BlockEntityType<StadiumBlockEntity> = this.create("stadium_terminal", BlockEntityType.Builder.of(::StadiumBlockEntity, CobblemonBlocks.STADIUM).build(null))
@JvmField
val LECTERN: BlockEntityType<LecternBlockEntity> = this.create("lectern", BlockEntityType.Builder.of(::LecternBlockEntity, CobblemonBlocks.LECTERN).build(null))
@@ -354,6 +354,9 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val PC = create("pc", PCBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).strength(2F).noOcclusion().lightLevel { if ((it.getValue(PCBlock.ON) as Boolean) && (it.getValue(PCBlock.PART) == PCBlock.PCPart.TOP)) 10 else 0 }))
@JvmField
val STADIUM = create("stadium_terminal", StadiumBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).strength(2F)))
@JvmField
val LECTERN = create("lectern", LecternBlock(BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).sound(SoundType.WOOD).strength(2.5F).ignitedByLava()))
@@ -272,6 +272,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val PC = blockItem("pc", CobblemonBlocks.PC)
@JvmField
val STADIUM = blockItem("stadium_terminal", CobblemonBlocks.STADIUM)
@JvmField
val PASTURE = blockItem("pasture", CobblemonBlocks.PASTURE)
@JvmField
val DISPLAY_CASE = blockItem("display_case", CobblemonBlocks.DISPLAY_CASE)
@@ -293,20 +295,21 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField val REAPER_CLOTH = noSettingsItem("reaper_cloth")
@JvmField val PRISM_SCALE = noSettingsItem("prism_scale")
@JvmField val SACHET = noSettingsItem("sachet")
@JvmField val WHIPPED_DREAM = noSettingsItem("whipped_dream")
@JvmField val STRAWBERRY_SWEET = noSettingsItem("strawberry_sweet")
@JvmField val LOVE_SWEET = noSettingsItem("love_sweet")
@JvmField val BERRY_SWEET = noSettingsItem("berry_sweet")
@JvmField val CLOVER_SWEET = noSettingsItem("clover_sweet")
@JvmField val FLOWER_SWEET = noSettingsItem("flower_sweet")
@JvmField val STAR_SWEET = noSettingsItem("star_sweet")
@JvmField val RIBBON_SWEET = noSettingsItem("ribbon_sweet")
@JvmField val WHIPPED_DREAM = create("whipped_dream", foodItem(8, 0.3f))
@JvmField val STRAWBERRY_SWEET = create("strawberry_sweet", foodItem(6, 0.125f))
@JvmField val LOVE_SWEET = create("love_sweet", foodItem(6, 0.125f))
@JvmField val BERRY_SWEET = create("berry_sweet", foodItem(6, 0.125f))
@JvmField val CLOVER_SWEET = create("clover_sweet", foodItem(6, 0.125f))
@JvmField val FLOWER_SWEET = create("flower_sweet", foodItem(6, 0.125f))
@JvmField val STAR_SWEET = create("star_sweet", foodItem(6, 0.125f))
@JvmField val RIBBON_SWEET = create("ribbon_sweet", foodItem(6, 0.125f))
@JvmField val CHIPPED_POT = noSettingsItem("chipped_pot")
@JvmField val CRACKED_POT = noSettingsItem("cracked_pot")
@JvmField val MASTERPIECE_TEACUP = noSettingsItem("masterpiece_teacup")
@JvmField val UNREMARKABLE_TEACUP = noSettingsItem("unremarkable_teacup")
@JvmField val SWEET_APPLE = noSettingsItem("sweet_apple")
@JvmField val TART_APPLE = noSettingsItem("tart_apple")
@JvmField val SWEET_APPLE = create("sweet_apple", foodItem(4, 0.3f))
@JvmField val TART_APPLE = create("tart_apple", foodItem(4, 0.3f))
@JvmField val SYRUPY_APPLE = create("syrupy_apple", foodItem(4, 0.3f))
@JvmField val GALARICA_CUFF = noSettingsItem("galarica_cuff")
@JvmField val GALARICA_WREATH = noSettingsItem("galarica_wreath")
@JvmField val BLACK_AUGURITE = noSettingsItem("black_augurite")
@@ -1358,4 +1361,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
return createdItem
}
private fun foodItem(nutrition: Int, saturationModifier: Float): Item {
return Item(Item.Properties().food(FoodProperties.Builder().nutrition(nutrition).saturationModifier(saturationModifier).build()))
}
}
@@ -218,6 +218,10 @@ import com.cobblemon.mod.common.net.serverhandling.trade.ChangeTradeAcceptanceHa
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.stadium.StadiumCamerasSyncPacket
import com.cobblemon.mod.common.stadium.StadiumJoinHandler
import com.cobblemon.mod.common.stadium.StadiumJoinPacket
import com.cobblemon.mod.common.stadium.StadiumCameraManagersSyncPacket
import com.cobblemon.mod.common.util.server
import net.minecraft.server.level.ServerPlayer
@@ -374,6 +378,8 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(FlowRegistrySyncPacket.ID, FlowRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(CosmeticItemAssignmentSyncPacket.ID, CosmeticItemAssignmentSyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(MarkRegistrySyncPacket.ID, MarkRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(StadiumCamerasSyncPacket.ID, StadiumCamerasSyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(StadiumCameraManagersSyncPacket.ID, StadiumCameraManagersSyncPacket::decode, DataRegistrySyncPacketHandler()))
// Effects
list.add(PacketRegisterInfo(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler))
@@ -436,6 +442,9 @@ object CobblemonNetwork {
// Riding
list.add(PacketRegisterInfo(ClientboundUpdateRidingStatePacket.ID, ClientboundUpdateRidingStatePacket::decode, ClientboundUpdateRidingStateHandler))
// Stadium packets
list.add(PacketRegisterInfo(StadiumJoinPacket.ID, StadiumJoinPacket::decode, StadiumJoinHandler))
return list
}
@@ -832,6 +832,7 @@ object MoLangFunctions {
map.put("is_moving") { DoubleValue((pokemonEntity.moveControl as? PokemonMoveControl)?.hasWanted() == true) }
map.put("is_flying") { DoubleValue(pokemonEntity.getBehaviourFlag(PokemonBehaviourFlag.FLYING)) }
map.put("is_gliding") { DoubleValue(pokemonEntity.useRidingAltPose()) }
map.put("is_ridden") { DoubleValue(pokemonEntity.hasControllingPassenger()) }
map.put("has_aspect") { DoubleValue(it.getString(0) in pokemonEntity.aspects) }
map.put("is_pokemon") { DoubleValue.ONE }
map.put("is_holding_item") { DoubleValue(!pokemonEntity.entityData.get(PokemonEntity.SHOWN_HELD_ITEM).let {
@@ -107,4 +107,22 @@ open class OrientationController(val entity: LivingEntity) {
val roll: Float
get() = Mth.wrapDegrees(-upVector.angleSigned(UP, forwardVector).toDegrees())
fun applyGlobalYaw(deltaYawDegrees: Float) = updateOrientation { original ->
val euler = Vector3f()
original.getEulerAnglesXYZ(euler)
val pitch0 = euler.x
val roll0 = euler.z
val unroll = Matrix3f().rotateZ(-roll0)
val unpitch = Matrix3f().rotateX(-pitch0)
val flattened = Matrix3f(original).mul(unroll).mul(unpitch)
//Flip to reflect current acceptance of what direction is pos for yaw
val globalYaw = Matrix3f().rotationY(-1.0f * deltaYawDegrees.toRadians())
val rePitch = Matrix3f().rotateX(pitch0)
val reRoll = Matrix3f().rotateZ(roll0)
return@updateOrientation Matrix3f(globalYaw).mul(flattened).mul(rePitch).mul(reRoll)
}
}
@@ -77,18 +77,18 @@ object CatchRateModifiers {
/**
* Used by [PokeBalls.MOON_BALL].
* Boosts the catch rate 1.5× during Moon Phases 3 and 7 between the times of 12000 – 24000.
* 2.5× during Moon Phases 2 and 8 between the times of 12000 – 24000.
* 4× during Moon Phase 1 between the times of 12000 – 24000.
* Boosts the catch rate 1.5× during Moon Phases 2 and 6 between the times of 12000 – 24000.
* 2.5× during Moon Phases 1 and 7 between the times of 12000 – 24000.
* 4× during Moon Phase 0 between the times of 12000 – 24000.
* 1× otherwise.
*/
val MOON_PHASES: CatchRateModifier = WorldStateModifier { _, entity ->
if (entity.level().gameTime in 12000..24000)
return@WorldStateModifier 1F
when (entity.level().moonPhase) {
3, 7 -> 1.5F
2, 8 -> 2.5F
1 -> 4F
2, 6 -> 1.5F
1, 7 -> 2.5F
0 -> 4F
else -> 1F
}
}
@@ -24,11 +24,11 @@ import net.minecraft.world.phys.Vec3
*/
open class RidingBehaviourState {
open val rideVelocity: SidedRidingState<Vec3> = ridingState(Vec3.ZERO, Side.BOTH)
open val stamina: SidedRidingState<Float> = ridingState(0F, Side.BOTH)
open val stamina: SidedRidingState<Float> = ridingState(1.0F, Side.BOTH)
open fun reset() {
rideVelocity.set(Vec3.ZERO, true)
stamina.set(0F, true)
stamina.set(1.0F, true)
}
open fun copy(): RidingBehaviourState {
@@ -25,6 +25,7 @@ object RidingBehaviours {
register(JetAirBehaviour.KEY, JetAirBehaviour())
register(SwimDashBehaviour.KEY, SwimDashBehaviour())
register(VehicleLandBehaviour.KEY, VehicleLandBehaviour())
register(HoverBehaviour.KEY, HoverBehaviour())
register(CompositeBehaviour.KEY, CompositeBehaviour())
}
@@ -41,6 +41,11 @@ class RidingController<Settings : RidingBehaviourSettings, State : RidingBehavio
return behaviour.speed(settings, state, vehicle, driver)
}
override fun clampPassengerRotation(settings: Settings, state: State, vehicle: PokemonEntity, driver: LivingEntity) {
if (!isActive(settings, state, vehicle)) return
return behaviour.clampPassengerRotation(settings, state, vehicle, driver)
}
override fun rotation(settings: Settings, state: State, vehicle: PokemonEntity, driver: LivingEntity): Vec2 {
if (!isActive(settings, state, vehicle)) return driver.rotationVector
return behaviour.rotation(settings, state, vehicle, driver)
@@ -27,6 +27,9 @@ import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
import org.joml.Matrix3f
import org.joml.Quaternionf
import org.joml.Vector3f
import kotlin.math.*
class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
@@ -179,26 +182,26 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
}
//Lateral movement based on driver input.
val latTopSpeed = topSpeed / 2.0
if (driver.xxa != 0.0f && state.stamina.get() > 0.0) {
newVelocity = Vec3(
(newVelocity.x + (accel * driver.xxa)).coerceIn(-latTopSpeed, latTopSpeed),
newVelocity.y,
newVelocity.z)
activeInput = true
}
else {
newVelocity = Vec3(
lerp(newVelocity.x, 0.0, latTopSpeed / 20.0),
newVelocity.y,
newVelocity.z)
}
// val latTopSpeed = topSpeed / 2.0
// if (driver.xxa != 0.0f && state.stamina.get() > 0.0) {
// newVelocity = Vec3(
// (newVelocity.x + (accel * driver.xxa)).coerceIn(-latTopSpeed, latTopSpeed),
// newVelocity.y,
// newVelocity.z)
// activeInput = true
// }
// else {
// newVelocity = Vec3(
// lerp(newVelocity.x, 0.0, latTopSpeed / 20.0),
// newVelocity.y,
// newVelocity.z)
// }
//Vertical movement based on driver input.
val vertTopSpeed = topSpeed / 2.0
val vertInput = when {
driver.jumping -> 1.0
driver.isShiftKeyDown -> -1.0
driver.jumping && state.rideVelocity.get().length() < 0.3 -> 1.0
driver.isShiftKeyDown && state.rideVelocity.get().length() < 0.3 -> -1.0
else -> 0.0
}
@@ -225,23 +228,24 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
}
}
//Only perform stamina logic if the ride does not have infinite stamina
if (!vehicle.runtime.resolveBoolean(settings.infiniteStamina)) {
if (activeInput) {
state.stamina.set(state.stamina.get() - (0.05 / staminaStat).toFloat())
}
//Lose a base amount of stamina just for being airborne
state.stamina.set(state.stamina.get() - (0.01 / staminaStat).toFloat())
}
else
{
state.stamina.set(1.0f)
}
//TODO: Reintroduce stamina drain once stats start to be polished and tweaked
// //Only perform stamina logic if the ride does not have infinite stamina
// if (!vehicle.runtime.resolveBoolean(settings.infiniteStamina)) {
// if (activeInput) {
// state.stamina.set(state.stamina.get() - (0.05 / staminaStat).toFloat())
// }
//
// //Lose a base amount of stamina just for being airborne
// state.stamina.set(state.stamina.get() - (0.01 / staminaStat).toFloat())
// }
// else
// {
// state.stamina.set(1.0f)
// }
//air resistance
if( abs(newVelocity.z) > 0) {
newVelocity = newVelocity.subtract(0.0, 0.0, min(0.003 * newVelocity.z.sign, newVelocity.z))
newVelocity = newVelocity.subtract(0.0, 0.0, min(0.0015 * newVelocity.z.sign, newVelocity.z))
}
state.rideVelocity.set(newVelocity)
}
@@ -256,10 +260,17 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
if (driver !is OrientationControllable) return Vec3.ZERO
val controller = (driver as OrientationControllable).orientationController
//TODO: Tie into handling
//limit rolling based on handling and current speed.
//modulated by speed so that when flapping idle in air you are ont wobbling around to look around
//TODO: Tie handling into yaw rate
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
val rotationChangeRate = 10.0
//This rotation limit will be used to know if the ride has exceeded it and its needs correcting.
val rotMin = 15.0
val rotLimit = max(handling * sqrt(normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed)), rotMin)
val rotationChangeRate = 100.0
var yawForce = rotationChangeRate * sin(Math.toRadians(controller.roll.toDouble()))
//for a bit of correction on the rolls limit it to a quarter the amount
@@ -269,7 +280,28 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
yawForce *= abs(cos(Math.toRadians(controller.pitch.toDouble())))
pitchForce *= abs(cos(Math.toRadians(controller.pitch.toDouble()))) * 1.5
return Vec3(yawForce, pitchForce, 0.0)
var yawDeltaDeg = deltaTime * rotationChangeRate * sin(Math.toRadians(controller.roll.toDouble())) //sin(Math.toRadians(controller.roll.toDouble())) * abs(cos(Math.toRadians(controller.pitch.toDouble())))
val trueYawDelt = yawDeltaDeg * abs(cos(Math.toRadians(controller.pitch.toDouble())))
//val pitchedYawDelt = yawDeltaDeg - trueYawDelt
controller.applyGlobalYaw(trueYawDelt.toFloat())
val correctionRate = 5.0
//Calculate correcting roll force.
if(abs(controller.roll) > rotLimit) {
state.currRollCorrectionForce.set(
state.currRollCorrectionForce.get() + ((abs(controller.roll) - rotLimit) / 180 - rotLimit) * controller.roll.sign * correctionRate * deltaTime * 0.01
)
} else {
state.currRollCorrectionForce.set(
//reduce rollCorrection gradually and make sure to
//state.currRollCorrectionForce.get() - max(correctionRate * deltaTime * 0.04, abs(state.currRollCorrectionForce.get())) * state.currRollCorrectionForce.get().sign
lerp(state.currRollCorrectionForce.get(), 0.0, deltaTime * 0.98)
)
}
//yaw, pitch, roll
return Vec3(0.0, 0.0, state.currRollCorrectionForce.get())
}
override fun rotationOnMouseXY(
@@ -303,13 +335,14 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
//modulated by speed so that when flapping idle in air you are ont wobbling around to look around
val rotMin = 15.0
var rollForce = xInput
val rotLimit = max(handling * normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed).pow(3), rotMin)
val rotLimit = max(handling * sqrt(normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed)), rotMin)
//Limit roll by non linearly decreasing inputs towards
// a rotation limit based on the current distance from
// that rotation limit
if (abs(controller.roll + rollForce) < rotLimit) {
if (sign(rollForce) == sign(controller.roll).toDouble()) {
//Grab how far the current roll is away from the roll limit
val d = abs(abs(controller.roll) - rotLimit)
rollForce *= (d.pow(2)) / (rotLimit.pow(2))
}
@@ -318,10 +351,18 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
}
//Give the ability to yaw with x mouse input when at low speeds.
val yawForce = xInput * ( 1.0 - normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed).pow(3))
val yawForce = xInput * ( 1.0 - sqrt(normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed)))
//Yaw locally a bit when up or down so that its more intuitive to make it out of a dive or a straight vertical
//climb
val yawForcePitched = xInput * sin(Math.toRadians(abs(controller.pitch.toDouble()))) * 0.25
//Apply yaw globally as we don't want roll or pitch changes due to local yaw when looking up or down.
controller.applyGlobalYaw(yawForce.toFloat())
//yaw, pitch, roll
return Vec3(yawForce, yInput, rollForce)
return Vec3(yawForcePitched, yInput, rollForce)
}
/*
@@ -486,6 +527,7 @@ class BirdAirSettings : RidingBehaviourSettings {
class BirdAirState : RidingBehaviourState() {
var gliding = ridingState(false, Side.CLIENT)
var lastGlide = ridingState(-100L, Side.CLIENT)
var currRollCorrectionForce = ridingState(0.0, Side.CLIENT)
override fun encode(buffer: FriendlyByteBuf) {
super.encode(buffer)
@@ -502,6 +544,7 @@ class BirdAirState : RidingBehaviourState() {
super.reset()
gliding.set(false, forced = true)
lastGlide.set(-100L, forced = true)
currRollCorrectionForce.set(0.0, forced = true)
}
override fun toString(): String {
@@ -513,11 +556,12 @@ class BirdAirState : RidingBehaviourState() {
it.stamina.set(this.stamina.get(), forced = true)
it.gliding.set(this.gliding.get(), forced = true)
it.lastGlide.set(this.lastGlide.get(), forced = true)
it.currRollCorrectionForce.set(this.currRollCorrectionForce.get(), forced = true)
}
override fun shouldSync(previous: RidingBehaviourState): Boolean {
if (previous !is BirdAirState) return false
if (previous.gliding != gliding) return true
if (previous.gliding.get() != gliding.get()) return true
return super.shouldSync(previous)
}
}
@@ -9,7 +9,7 @@
package com.cobblemon.mod.common.api.riding.behaviour.types
import com.bedrockk.molang.Expression
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.MoLangMath.lerp
import com.cobblemon.mod.common.api.riding.RidingStyle
import com.cobblemon.mod.common.api.riding.behaviour.*
import com.cobblemon.mod.common.api.riding.posing.PoseOption
@@ -18,15 +18,14 @@ import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.*
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.util.Mth
import net.minecraft.util.SmoothDouble
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
import net.minecraft.world.phys.shapes.Shapes
import kotlin.math.max
import kotlin.math.min
import kotlin.math.pow
import kotlin.math.*
class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandState> {
companion object {
@@ -38,7 +37,7 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
val poseProvider = PoseProvider<GenericLandSettings, GenericLandState>(PoseType.STAND)
.with(PoseOption(PoseType.WALK) { _, state, _ ->
return@PoseOption state.rideVelocity.get().z > 0.1
return@PoseOption abs(state.rideVelocity.get().z) > 0.2
})
override fun isActive(
@@ -77,15 +76,99 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
return state.rideVelocity.get().length().toFloat()
}
override fun updatePassengerRotation(
settings: GenericLandSettings,
state: GenericLandState,
vehicle: PokemonEntity,
driver: LivingEntity
) {
//Take the inverse so that it cancels out how
//much the entity rotates.
val turnAmount = calcRotAmount(settings, state, vehicle, driver)
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
val maxYawDiff = 90.0f
//Normalize the current rotation diff
val rotMod = Mth.wrapDegrees(driver.yRot - vehicle.yRot) / maxYawDiff
val rotAmount = 10.0f
//Take the inverse so that you turn more at higher speeds
val normSpeed = 1.0f - 0.5f*normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed).toFloat()
//driver.yRot += (entity.riding.deltaRotation.y - turnAmount)
//driver.setYHeadRot(driver.yHeadRot + (entity.riding.deltaRotation.y) - turnAmount)
}
override fun clampPassengerRotation(
settings: GenericLandSettings,
state: GenericLandState,
vehicle: PokemonEntity,
driver: LivingEntity
) {
val f = Mth.wrapDegrees(driver.yRot - vehicle.yRot)
val lookYawLimit = 90.0f
val g = Mth.clamp(f, -lookYawLimit, lookYawLimit)
driver.yRotO += g - f
driver.yRot = driver.yRot + g - f
driver.setYHeadRot(driver.yRot)
}
override fun rotation(
settings: GenericLandSettings,
state: GenericLandState,
vehicle: PokemonEntity,
driver: LivingEntity
): Vec2 {
return Vec2(driver.xRot * 0.5f, driver.yRot)
val turnAmount = calcRotAmount(settings, state, vehicle, driver)
return Vec2(vehicle.xRot, vehicle.yRot + turnAmount )
}
/*
* Calculates the rotation amount given the difference between
* the current player y rot and entity y rot. This gives the
* affect of influencing a rides rotation through the mouse
* without it being instant.
*/
fun calcRotAmount(
settings: GenericLandSettings,
state: GenericLandState,
vehicle: PokemonEntity,
driver: LivingEntity
): Float {
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
//In degrees per second
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
val maxYawDiff = 90.0f
//Normalize the current rotation diff
val rotDiff = Mth.wrapDegrees(driver.yRot - vehicle.yRot)
val rotDiffNorm = rotDiff / maxYawDiff
//Take the square root so that the ride levels out quicker when at lower differences between entity
//y and driver y
//This influences the speed of the turn based on how far in one direction you're looking
val rotDiffMod = (sqrt(abs(rotDiffNorm)) * rotDiffNorm.sign)
//Take the inverse so that you turn less at higher speeds
val normSpeed = 1.0f // = 1.0f - 0.5f*normalizeVal(state.rideVelocityocity.length(), 0.0, topSpeed).toFloat()
// TODO: This needs to be tweaked with in game results and testing
val turnRate = (handling.toFloat() / 20.0f) * 2
//Ensure you only ever rotate as much difference as there is between the angles.
val turnSpeed = turnRate * rotDiffMod * normSpeed
val rotAmount = turnSpeed.coerceIn(-abs(rotDiff), abs(rotDiff))
return rotAmount
}
override fun velocity(
settings: GenericLandSettings,
state: GenericLandState,
@@ -93,24 +176,16 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
driver: Player,
input: Vec3
): Vec3 {
val runtime = vehicle.runtime
val driveFactor = runtime.resolveFloat(settings.driveFactor)
val strafeFactor = runtime.resolveFloat(settings.strafeFactor)
val f = driver.xxa * strafeFactor
var g = driver.zza * driveFactor
if (g <= 0.0f) {
g *= runtime.resolveFloat(settings.reverseDriveFactor)
}
val gravity = -1.0
//Limit horizontal velocity that may have accumulated through alternate behaviour
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
val currVel = state.rideVelocity.get()
// state.rideVelocity.set(Vec3(
// max(currVel.x, topSpeed),
// currVel.y,
// max(currVel.z, topSpeed)
// ))
val newVelocity = calculateRideSpaceVel(settings, state, vehicle, driver)
//Jump the thang!
if (driver.jumping && vehicle.onGround()) {
state.rideVelocity.set(Vec3(newVelocity.x, 2.0, newVelocity.z))
} else {
state.rideVelocity.set(newVelocity)
}
state.rideVelocity.set(calculateRideSpaceVel(settings, state, vehicle, driver))
//This is cheap.
//Also make it stop quicker the slower it is.
@@ -129,35 +204,59 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
vehicle: PokemonEntity,
driver: Player
): Vec3 {
val topSpeed = vehicle.runtime.resolveDouble(settings.topSpeedExpr)
val accel = vehicle.runtime.resolveDouble(settings.accelExpr)
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr)
val speed = state.rideVelocity.get().length()
val minSpeed = 0.0
//Flag for determining if player is actively inputting
var activeInput = false
var newVelocity = Vec3(state.rideVelocity.get().x, state.rideVelocity.get().y, state.rideVelocity.get().z)
//speed up and slow down based on input
if (driver.zza > 0.0 && speed <= topSpeed && state.stamina.get() > 0.0f) {
//modify acceleration to be slower when at closer speeds to top speed
val accelMod = max((normalizeSpeed(speed, minSpeed, topSpeed) - 1).pow(2), 0.1)
newVelocity = Vec3(newVelocity.x, newVelocity.y, min(newVelocity.z + (accel * accelMod), topSpeed))
} else if (driver.zza >= 0.0 && state.stamina.get() == 0.0f || speed > topSpeed) {
newVelocity = Vec3(newVelocity.x, newVelocity.y, max(newVelocity.z - ((accel) / 4), minSpeed))
} else if (driver.zza < 0.0 && speed > minSpeed) {
//modify deccel to be slower when at closer speeds to minimum speed
val deccelMod = max(-(normalizeSpeed(speed, minSpeed, topSpeed)) + 1, 0.0)
//Decelerate currently always a constant half of max acceleration.
newVelocity =
Vec3(newVelocity.x, newVelocity.y, max(newVelocity.z - ((accel * deccelMod) / 2), minSpeed))
//speed up and slow down based on input
if (driver.zza != 0.0f && state.stamina.get() > 0.0) {
//make sure it can't exceed top speed
val forwardInput = when {
driver.zza > 0 && newVelocity.z > topSpeed -> 0.0
driver.zza < 0 && newVelocity.z < (-topSpeed / 3.0) -> 0.0
else -> driver.zza.sign
}
newVelocity = Vec3(
newVelocity.x,
newVelocity.y,
(newVelocity.z + (accel * forwardInput.toDouble())))
activeInput = true
}
//Gravity logic
if (vehicle.onGround()) {
newVelocity = Vec3(newVelocity.x, 0.0, newVelocity.z)
} else {
newVelocity = Vec3(newVelocity.x, max(newVelocity.y - 0.2, -1.0), newVelocity.z)
val gravity = (9.8 / ( 20.0)) * 0.2
val terminalVel = 2.0
val fallingForce = gravity - ( newVelocity.z.sign *gravity *(abs(newVelocity.z) / 2.0))
newVelocity = Vec3(newVelocity.x, max(newVelocity.y - fallingForce, -terminalVel), newVelocity.z)
}
//ground Friction
if( abs(newVelocity.z) > 0 && vehicle.onGround() && !activeInput) {
newVelocity = newVelocity.subtract(0.0, 0.0, min(0.03 * newVelocity.z.sign, newVelocity.z))
}
//Jump the thang!
if (driver.jumping && vehicle.onGround()) {
val jumpVel = 1.0
newVelocity = newVelocity.add(0.0, 1.0, 0.0)
//Ensure this doesn't add unwanted forward velocity
val mag = if(newVelocity.length() < topSpeed) newVelocity.length() else topSpeed
newVelocity = newVelocity.normalize().scale(mag)
}
return newVelocity
}
@@ -165,7 +264,7 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
* Normalizes the current speed between minSpeed and maxSpeed.
* The result is clamped between 0.0 and 1.0, where 0.0 represents minSpeed and 1.0 represents maxSpeed.
*/
private fun normalizeSpeed(currSpeed: Double, minSpeed: Double, maxSpeed: Double): Double {
private fun normalizeVal(currSpeed: Double, minSpeed: Double, maxSpeed: Double): Double {
require(maxSpeed > minSpeed) { "maxSpeed must be greater than minSpeed" }
return ((currSpeed - minSpeed) / (maxSpeed - minSpeed)).coerceIn(0.0, 1.0)
}
@@ -217,8 +316,6 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
driver: Player
): Float {
//Retrieve stamina from state and tick up at a rate of 0.1 a second
val staminaGain = (1.0 / 20.0) * 0.1
state.stamina.set(min(state.stamina.get() + staminaGain, 1.0).toFloat())
return (state.stamina.get() / 1.0f)
}
@@ -229,10 +326,7 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
driver: Player,
jumpStrength: Int
): Vec3 {
val runtime = vehicle.runtime
runtime.environment.query.addFunction("jump_strength") { DoubleValue(jumpStrength.toDouble()) }
val jumpVector = settings.jumpVector.map { runtime.resolveFloat(it) }
return Vec3(jumpVector[0].toDouble(), jumpVector[1].toDouble(), jumpVector[2].toDouble())
return Vec3.ZERO
}
override fun gravity(
@@ -324,24 +418,15 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
class GenericLandSettings : RidingBehaviourSettings {
override val key = GenericLandBehaviour.KEY
var driveFactor = "1.0".asExpression()
var canJump = "true".asExpression()
private set
var strafeFactor = "0.2".asExpression()
private set
var reverseDriveFactor = "0.25".asExpression()
private set
var topSpeedExpr: Expression = "q.get_ride_stats('SPEED', 'LAND', 1.0, 0.3)".asExpression()
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'LAND', 1.0, 0.3)".asExpression()
private set
// Max accel is a whole 1.0 in 1 second. The conversion in the function below is to convert seconds to ticks
var accelExpr: Expression =
"q.get_ride_stats('ACCELERATION', 'LAND', (1.0 / (20.0 * 0.5)), (1.0 / (20.0 * 5.0)))".asExpression()
private set
var jumpVector = listOf("0".asExpression(), "0.3".asExpression(), "0".asExpression())
var accelerationExpr: Expression =
"q.get_ride_stats('ACCELERATION', 'LAND', (1.0 / (20.0 * 1.5)), (1.0 / (20.0 * 5.0)))".asExpression()
private set
// Between 30 seconds and 10 seconds at the lowest when at full speed.
@@ -357,30 +442,16 @@ class GenericLandSettings : RidingBehaviourSettings {
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeResourceLocation(key)
buffer.writeExpression(driveFactor)
buffer.writeExpression(strafeFactor)
buffer.writeExpression(reverseDriveFactor)
buffer.writeExpression(topSpeedExpr)
buffer.writeExpression(accelExpr)
buffer.writeExpression(jumpVector[0])
buffer.writeExpression(jumpVector[1])
buffer.writeExpression(jumpVector[2])
buffer.writeExpression(speedExpr)
buffer.writeExpression(accelerationExpr)
buffer.writeExpression(staminaExpr)
buffer.writeExpression(jumpExpr)
buffer.writeExpression(handlingExpr)
}
override fun decode(buffer: RegistryFriendlyByteBuf) {
driveFactor = buffer.readExpression()
strafeFactor = buffer.readExpression()
reverseDriveFactor = buffer.readExpression()
topSpeedExpr = buffer.readExpression()
accelExpr = buffer.readExpression()
jumpVector = listOf(
buffer.readExpression(),
buffer.readExpression(),
buffer.readExpression()
)
speedExpr = buffer.readExpression()
accelerationExpr = buffer.readExpression()
staminaExpr = buffer.readExpression()
jumpExpr = buffer.readExpression()
handlingExpr = buffer.readExpression()
@@ -394,7 +465,6 @@ class GenericLandState : RidingBehaviourState() {
override fun copy() = GenericLandState().also {
it.rideVelocity.set(this.rideVelocity.get(), forced = true)
it.stamina.set(this.stamina.get(), forced = true)
it.currSpeed.set(this.currSpeed.get(), forced = true)
}
override fun shouldSync(previous: RidingBehaviourState): Boolean {
@@ -0,0 +1,479 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding.behaviour.types
import com.bedrockk.molang.Expression
import com.bedrockk.molang.runtime.MoLangMath.lerp
import com.cobblemon.mod.common.api.riding.RidingStyle
import com.cobblemon.mod.common.api.riding.behaviour.*
import com.cobblemon.mod.common.api.riding.posing.PoseOption
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.*
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.util.Mth
import net.minecraft.util.SmoothDouble
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
import net.minecraft.world.phys.shapes.Shapes
import kotlin.math.*
class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
companion object {
val KEY = cobblemonResource("air/hover")
}
override val key = KEY
override val style = RidingStyle.AIR
val poseProvider = PoseProvider<HoverSettings, HoverState>(PoseType.STAND)
.with(PoseOption(PoseType.WALK) { _, state, _ ->
return@PoseOption abs(state.rideVelocity.get().z) > 0.2
})
override fun isActive(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity
): Boolean {
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
//Need to check other fluids
if (vehicle.isInWater || vehicle.isUnderWater) {
return@any false
}
//This might not actually work, depending on what the yPos actually is. yPos of the middle of the entity? the feet?
if (it.y.toDouble() == (vehicle.position().y)) {
val blockState = vehicle.level().getBlockState(it.below())
return@any !blockState.isAir && blockState.fluidState.isEmpty
}
true
}
}
override fun pose(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity
): PoseType {
return this.poseProvider.select(settings, state, vehicle)
}
override fun speed(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity,
driver: Player
): Float {
return state.rideVelocity.get().length().toFloat()
}
override fun updatePassengerRotation(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity,
driver: LivingEntity
) {
//Take the inverse so that it cancels out how
//much the entity rotates.
val turnAmount = calcRotAmount(settings, state, vehicle, driver)
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
val maxYawDiff = 90.0f
//Normalize the current rotation diff
val rotMod = Mth.wrapDegrees(driver.yRot - vehicle.yRot) / maxYawDiff
val rotAmount = 10.0f
//Take the inverse so that you turn more at higher speeds
val normSpeed = 1.0f - 0.5f*normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed).toFloat()
//driver.yRot += (entity.riding.deltaRotation.y - turnAmount)
//driver.setYHeadRot(driver.yHeadRot + (entity.riding.deltaRotation.y) - turnAmount)
}
override fun clampPassengerRotation(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity,
driver: LivingEntity
) {
val f = Mth.wrapDegrees(driver.yRot - vehicle.yRot)
val lookYawLimit = 90.0f
val g = Mth.clamp(f, -lookYawLimit, lookYawLimit)
driver.yRotO += g - f
driver.yRot = driver.yRot + g - f
driver.setYHeadRot(driver.yRot)
}
override fun rotation(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity,
driver: LivingEntity
): Vec2 {
val turnAmount = calcRotAmount(settings, state, vehicle, driver)
return Vec2(driver.xRot, vehicle.yRot + turnAmount )
}
/*
* Calculates the rotation amount given the difference between
* the current player y rot and entity y rot. This gives the
* affect of influencing a rides rotation through the mouse
* without it being instant.
*/
fun calcRotAmount(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity,
driver: LivingEntity
): Float {
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
//In degrees per second
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
val maxYawDiff = 90.0f
//Normalize the current rotation diff
val rotDiff = Mth.wrapDegrees(driver.yRot - vehicle.yRot)
val rotDiffNorm = rotDiff / maxYawDiff
//Take the square root so that the ride levels out quicker when at lower differences between entity
//y and driver y
//This influences the speed of the turn based on how far in one direction you're looking
val rotDiffMod = (sqrt(abs(rotDiffNorm)) * rotDiffNorm.sign)
//Take the inverse so that you turn less at higher speeds
val normSpeed = 1.0f // = 1.0f - 0.5f*normalizeVal(state.rideVelocityocity.length(), 0.0, topSpeed).toFloat()
// TODO: This needs to be tweaked with in game results and testing
val turnRate = (handling.toFloat() / 20.0f) * 2
//Ensure you only ever rotate as much difference as there is between the angles.
val turnSpeed = turnRate * rotDiffMod * normSpeed
val rotAmount = turnSpeed.coerceIn(-abs(rotDiff), abs(rotDiff))
return rotAmount
}
override fun velocity(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity,
driver: Player,
input: Vec3
): Vec3 {
val strafeFactor = 0.2
val f = driver.xxa * strafeFactor
var g = driver.zza
if (g <= 0.0f) {
g *= -1.0f
}
return calculateRideSpaceVel(settings, state, vehicle, driver).scale(10.0)
}
private fun calculateRideSpaceVel(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity,
driver: Player
): Vec3 {
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr)
val speed = state.rideVelocity.get().length()
//Flag for determining if player is actively inputting
var activeInput = false
val minSpeed = 0.0
var newVelocity = Vec3(state.rideVelocity.get().x, state.rideVelocity.get().y, state.rideVelocity.get().z)
var jumpVec = Vec3.ZERO
//speed up and slow down based on input
if (driver.zza != 0.0f && state.stamina.get() > 0.0) {
//make sure it can't exceed top speed
val forwardInput = when {
driver.zza > 0 && newVelocity.z > topSpeed -> 0.0
driver.zza < 0 && newVelocity.z < (-topSpeed / 3.0) -> 0.0
else -> driver.zza.sign
}
newVelocity = Vec3(
newVelocity.x,
newVelocity.y,
(newVelocity.z + (accel * forwardInput.toDouble())))
activeInput = true
jumpVec = jumpVec.add(0.0, 0.0, forwardInput.toDouble())
}
//speed up and slow down based on input
if (driver.xxa != 0.0f && state.stamina.get() > 0.0) {
//make sure it can't exceed top speed
val forwardInput = when {
driver.xxa > 0 && newVelocity.x > topSpeed -> 0.0
driver.xxa < 0 && newVelocity.x < (-topSpeed / 3.0) -> 0.0
else -> driver.xxa.sign
}
newVelocity = Vec3(
newVelocity.x + (accel * forwardInput.toDouble()),
newVelocity.y,
(newVelocity.z ))
activeInput = true
}
//Vertical movement based on driver input.
val vertTopSpeed = topSpeed / 2.0
val vertInput = when {
driver.jumping -> 1.0
driver.isShiftKeyDown -> -1.0
else -> 0.0
}
if (vertInput != 0.0 && state.stamina.get() > 0.0) {
newVelocity = Vec3(
newVelocity.x,
(newVelocity.y + (accel * vertInput)).coerceIn(-vertTopSpeed, vertTopSpeed),
newVelocity.z)
activeInput = true
}
//air Friction
return newVelocity
}
/*
* Normalizes the current speed between minSpeed and maxSpeed.
* The result is clamped between 0.0 and 1.0, where 0.0 represents minSpeed and 1.0 represents maxSpeed.
*/
private fun normalizeVal(currSpeed: Double, minSpeed: Double, maxSpeed: Double): Double {
require(maxSpeed > minSpeed) { "maxSpeed must be greater than minSpeed" }
return ((currSpeed - minSpeed) / (maxSpeed - minSpeed)).coerceIn(0.0, 1.0)
}
override fun angRollVel(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity,
driver: Player,
deltaTime: Double
): Vec3 {
return Vec3.ZERO
}
override fun rotationOnMouseXY(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity,
driver: Player,
mouseY: Double,
mouseX: Double,
mouseYSmoother: SmoothDouble,
mouseXSmoother: SmoothDouble,
sensitivity: Double,
deltaTime: Double
): Vec3 {
//Smooth out mouse input.
val smoothingSpeed = 4
val xInput = mouseXSmoother.getNewDeltaValue(mouseX * 0.1, deltaTime * smoothingSpeed);
val yInput = mouseYSmoother.getNewDeltaValue(mouseY * 0.1, deltaTime * smoothingSpeed);
//yaw, pitch, roll
return Vec3(0.0, yInput, xInput)
}
override fun canJump(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity,
driver: Player
): Boolean {
return false
}
override fun setRideBar(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity,
driver: Player
): Float {
//Retrieve stamina from state and use it to set the "stamina bar"
return (state.stamina.get() / 1.0f)
}
override fun jumpForce(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity,
driver: Player,
jumpStrength: Int
): Vec3 {
return Vec3.ZERO
}
override fun gravity(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity,
regularGravity: Double
): Double {
return 0.0
}
override fun rideFovMultiplier(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity,
driver: Player
): Float {
return 1.0f
}
override fun useAngVelSmoothing(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun useRidingAltPose(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity,
driver: Player
): Boolean {
return false
}
override fun inertia(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity
): Double {
return 0.05
}
override fun shouldRoll(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun turnOffOnGround(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun dismountOnShift(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun shouldRotatePokemonHead(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun shouldRotatePlayerHead(
settings: HoverSettings,
state: HoverState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun createDefaultState(settings: HoverSettings) = HoverState()
}
class HoverSettings : RidingBehaviourSettings {
override val key = HoverBehaviour.KEY
var canJump = "true".asExpression()
private set
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 1.0, 0.3)".asExpression()
private set
// Max accel is a whole 1.0 in 1 second. The conversion in the function below is to convert seconds to ticks
var accelerationExpr: Expression =
"q.get_ride_stats('ACCELERATION', 'AIR', (1.0 / (20.0 * 0.5)), (1.0 / (20.0 * 5.0)))".asExpression()
private set
// Between 30 seconds and 10 seconds at the lowest when at full speed.
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 30.0, 10.0)".asExpression()
private set
//Between a one block jump and a ten block jump
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 10.0, 1.0)".asExpression()
private set
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 140.0, 20.0)".asExpression()
private set
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeResourceLocation(key)
buffer.writeExpression(speedExpr)
buffer.writeExpression(accelerationExpr)
buffer.writeExpression(staminaExpr)
buffer.writeExpression(jumpExpr)
buffer.writeExpression(handlingExpr)
}
override fun decode(buffer: RegistryFriendlyByteBuf) {
speedExpr = buffer.readExpression()
accelerationExpr = buffer.readExpression()
staminaExpr = buffer.readExpression()
jumpExpr = buffer.readExpression()
handlingExpr = buffer.readExpression()
}
}
class HoverState : RidingBehaviourState() {
override fun copy() = HoverState().also {
it.rideVelocity.set(this.rideVelocity.get(), forced = true)
it.stamina.set(this.stamina.get(), forced = true)
}
override fun shouldSync(previous: RidingBehaviourState): Boolean {
if (previous !is HoverState) return false
return super.shouldSync(previous)
}
}
@@ -26,6 +26,7 @@ import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
import net.minecraft.world.phys.shapes.Shapes
import kotlin.math.*
class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
@@ -40,7 +41,18 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
.with(PoseOption(PoseType.FLY) { _, state, _ -> state.rideVelocity.get().z > 0.1 })
override fun isActive(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Boolean {
return true
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
//Need to check other fluids
if (vehicle.isInWater || vehicle.isUnderWater) {
return@any false
}
//This might not actually work, depending on what the yPos actually is. yPos of the middle of the entity? the feet?
if (it.y.toDouble() == (vehicle.position().y)) {
val blockState = vehicle.level().getBlockState(it.below())
return@any !(!blockState.isAir && blockState.fluidState.isEmpty)
}
true
}
}
override fun pose(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): PoseType {
@@ -55,22 +67,24 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
//retrieve minSpeed
val minSpeed = vehicle.runtime.resolveDouble(settings.minSpeed)
//Reduce stamina unless stamina is infinite
if (!vehicle.runtime.resolveBoolean(settings.infiniteStamina)) {
//Calculate stamina loss due to speed
//At max speed it will tick down 0.1 a second so the stamina will last ten seconds
//There has got to be a better way to express this equation. It interpolates between 0.5 and 1.0
var staminaRate = (normalizeSpeed(state.rideVelocity.get().length(), minSpeed, topSpeed))
//interpolate between 0.25 and 1.0 so that you always have at least a min of 0.25 stam loss
staminaRate = 0.25 + (0.75 * staminaRate.pow(3))
//Calculate stamina loss in seconds achievable at top speed
val staminaLoss = staminaRate * (1.0 / (20.0 * staminaStat))
state.stamina.set(max(state.stamina.get() - staminaLoss, 0.0).toFloat())
} else {
state.stamina.set(1.0f)
}
//TODO: Reintroduce stamina drain once stats start to be polished and tweaked
state.stamina.set(1.0f)
// //Reduce stamina unless stamina is infinite
// if (!vehicle.runtime.resolveBoolean(settings.infiniteStamina)) {
// //Calculate stamina loss due to speed
// //At max speed it will tick down 0.1 a second so the stamina will last ten seconds
// //There has got to be a better way to express this equation. It interpolates between 0.5 and 1.0
// var staminaRate = (normalizeSpeed(state.rideVelocity.get().length(), minSpeed, topSpeed))
//
// //interpolate between 0.25 and 1.0 so that you always have at least a min of 0.25 stam loss
// staminaRate = 0.25 + (0.75 * staminaRate.pow(3))
//
// //Calculate stamina loss in seconds achievable at top speed
// val staminaLoss = staminaRate * (1.0 / (20.0 * staminaStat))
// state.stamina.set(max(state.stamina.get() - staminaLoss, 0.0).toFloat())
// } else {
// state.stamina.set(1.0f)
// }
return state.rideVelocity.get().length().toFloat()
}
@@ -160,7 +174,7 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
state.rideVelocity.set(Vec3(state.rideVelocity.get().x, state.rideVelocity.get().y, max(state.rideVelocity.get().z - ((accel) / 4), minSpeed)))
} else if (driver.zza < 0.0 && speed > minSpeed) {
//modify deccel to be slower when at closer speeds to minimum speed
val deccelMod = max((normalizeSpeed(speed, minSpeed, topSpeed) - 1).pow(2), 0.1)
val deccelMod = max((normalizeSpeed(speed, minSpeed, topSpeed) - 1).pow(2) * 8, 0.1)
//Decelerate currently always a constant half of max acceleration.
state.rideVelocity.set(Vec3(state.rideVelocity.get().x, state.rideVelocity.get().y, max(state.rideVelocity.get().z - ((accel * deccelMod) / 2), minSpeed)))
@@ -212,8 +226,13 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
val invertRoll = if (Cobblemon.config.invertRoll) -1 else 1
val invertPitch = if (Cobblemon.config.invertPitch) -1 else 1
// Accumulate the mouse input
state.currMouseXForce.set((state.currMouseXForce.get() + (0.0015 * mouseX * invertRoll)).coerceIn(-1.0, 1.0))
// Smooth out and accumulate roll input
val smoothingSpeed = 4.0
val mouseXc = (mouseX).coerceIn(-60.0, 60.0)
val xInput = mouseXSmoother.getNewDeltaValue(mouseXc * 0.1 * invertRoll, deltaTime * smoothingSpeed);
// Accumulate the y mouse input for pitch
//state.currMouseXForce.set((state.currMouseXForce.get() + (0.0015 * mouseX * invertRoll)).coerceIn(-1.0, 1.0))
state.currMouseYForce.set((state.currMouseYForce.get() + (0.0015 * mouseY * invertPitch)).coerceIn(-1.0, 1.0))
//Get handling in degrees per second
@@ -235,8 +254,9 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
val pitchRot = handling * state.currMouseYForce.get()
//Roll is 1.5 times as fast as pitch
val rollRot = handling * 1.5 * state.currMouseXForce.get()
//val rollRot = handling * 1.5 * state.currMouseXForce.get()
val rollRot = handling * 1.5 * xInput.coerceIn(-1.0,1.0)
//yaw, pitch, roll
return Vec3(0.0, pitchRot, rollRot)
}
@@ -345,10 +365,10 @@ class JetAirSettings : RidingBehaviourSettings {
var gravity: Expression = "0".asExpression()
private set
var minSpeed: Expression = "1.2".asExpression()
var minSpeed: Expression = "0.8".asExpression()
private set
var handlingYawExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 25.0, 8.0)".asExpression()
var handlingYawExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 50.0, 25.0)".asExpression()
private set
// Make configurable by json
@@ -362,7 +382,7 @@ class JetAirSettings : RidingBehaviourSettings {
private set
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 140.0, 20.0)".asExpression()
private set
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 2.5, 1.0)".asExpression()
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 1.8, 1.0)".asExpression()
private set
var accelerationExpr: Expression = "q.get_ride_stats('ACCELERATION', 'AIR', (1.0 / (20.0 * 1.0)), (1.0 / (20.0 * 5.0)))".asExpression()
private set
@@ -399,8 +419,8 @@ class JetAirSettings : RidingBehaviourSettings {
class JetAirState : RidingBehaviourState() {
var currSpeed = ridingState(0.0, Side.CLIENT)
var currMouseXForce = ridingState(0.0, Side.BOTH)
var currMouseYForce = ridingState(0.0, Side.BOTH)
var currMouseXForce = ridingState(0.0, Side.CLIENT)
var currMouseYForce = ridingState(0.0, Side.CLIENT)
override fun encode(buffer: FriendlyByteBuf) {
super.encode(buffer)
@@ -424,8 +444,8 @@ class JetAirState : RidingBehaviourState() {
it.currSpeed.set(currSpeed.get(), forced = true)
it.stamina.set(stamina.get(), forced = true)
it.rideVelocity.set(rideVelocity.get(), forced = true)
it.currMouseXForce.set(currMouseXForce.get(), forced = true)
it.currMouseYForce.set(currMouseYForce.get(), forced = true)
// it.currMouseXForce.set(currMouseXForce.get(), forced = true)
// it.currMouseYForce.set(currMouseYForce.get(), forced = true)
}
override fun shouldSync(previous: RidingBehaviourState): Boolean {
@@ -387,6 +387,8 @@ class CompositeState(
super.reset()
activeController.set(defaultBehaviour, forced = true)
lastTransition.set(-100L, forced = true)
defaultBehaviourState.reset()
alternateBehaviourState.reset()
}
override fun copy(): CompositeState {
@@ -402,17 +404,23 @@ class CompositeState(
override fun shouldSync(previous: RidingBehaviourState): Boolean {
if (previous !is CompositeState) return false
if (previous.activeController.get() != activeController.get()) return true
if (defaultBehaviourState.shouldSync(previous.defaultBehaviourState)) return true
if (alternateBehaviourState.shouldSync(previous.alternateBehaviourState)) return true
return super.shouldSync(previous)
}
override fun encode(buffer: FriendlyByteBuf) {
super.encode(buffer)
buffer.writeResourceLocation(activeController.get())
defaultBehaviourState.encode(buffer)
alternateBehaviourState.encode(buffer)
}
override fun decode(buffer: FriendlyByteBuf) {
super.decode(buffer)
activeController.set(buffer.readResourceLocation(), forced = true)
defaultBehaviourState.decode(buffer)
alternateBehaviourState.decode(buffer)
}
}
@@ -43,6 +43,7 @@ interface CompositeRidingStrategy<T : CompositeSettings> {
) {
toState.stamina.set(fromState.stamina.get())
toState.rideVelocity.set(fromState.rideVelocity.get())
fromState.reset()
state.activeController.set(toSettings.key)
state.lastTransition.set(vehicle.level().gameTime)
val behaviour = RidingBehaviours.get(toSettings.key)
@@ -46,9 +46,11 @@ object RunStrategy : CompositeRidingStrategy<CompositeSettings> {
driver: Player
): Boolean {
if (state.activeController.get() == defaultSettings.key) return false
if (!entity.onGround()) return false
if (state.lastTransition.get() + 20 >= entity.level().gameTime) return false
val defaultBehaviour = RidingBehaviours.get(defaultSettings.key)
return !driver.isSprinting || defaultBehaviour.isActive(defaultSettings, state.defaultBehaviourState, entity)
val ret = defaultBehaviour.isActive(defaultSettings, state.defaultBehaviourState, entity)
return ret
}
private fun shouldTransitionToAlternate(
@@ -0,0 +1,143 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding.util
import com.cobblemon.mod.common.OrientationControllable
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.math.geometry.toRadians
import net.minecraft.util.Mth
import net.minecraft.world.phys.Vec3
import org.joml.Matrix3f
import org.joml.Quaternionf
import org.joml.Vector3f
/**
* Class to handle the updating and containment of ride data used in animation.
*
* @author Jackowes
* @since April 7th, 2025
*/
class RidingAnimationData
{
var prevOrientation: Matrix3f = Matrix3f()
var prevRot: Vec3 = Vec3.ZERO
var velocitySpring: Vec3Spring = Vec3Spring()
var rotSpring: Vec3Spring = Vec3Spring()
var rotDeltaSpring: Vec3Spring = Vec3Spring()
var localVelocitySpring: Vec3Spring = Vec3Spring()
fun update(entity: PokemonEntity) {
var currRot = Vec3.ZERO
var angDelta = Vec3.ZERO
// val stiffness = 90.0
// val damping = 18.0
val stiffness = 16.0
val damping = 8.0
// Update velocity first
val currentVelocity = Vec3(
entity.x - entity.xOld,
entity.y - entity.yOld,
entity.z - entity.zOld
)
val r = entity.ifRidingAvailableSupply(false) { behaviour, settings, state ->
behaviour.shouldRoll(settings, state, entity);
}
if( r ) {
//TODO: should this return?
val controller = (entity.firstPassenger as? OrientationControllable)?.orientationController ?: return
val orientation = controller.orientation ?: Matrix3f()
val currPitch = controller.pitch
val currYaw = controller.yaw
val currRoll = controller.roll
currRot = Vec3(currPitch.toDouble(), currYaw.toDouble(), currRoll.toDouble())
val currOrientation = orientation
/******************************************************
* Calculate current 3d euler rotation deltas in the
* entities local space
*****************************************************/
// Get current and previous orientation as quaternions
val currQuat = Quaternionf().setFromUnnormalized(currOrientation)
val prevQuat = Quaternionf().setFromUnnormalized(prevOrientation)
// Compute deltaQuat = current * inverse(previous)
val deltaQuat = Quaternionf(currQuat).mul(Quaternionf(prevQuat).invert())
// Transform delta into the local space of the current orientation
val localDeltaQuat = Quaternionf(currQuat).invert().mul(deltaQuat).mul(currQuat)
// Convert delta rotation to Euler angles
val euler = Vector3f()
localDeltaQuat.getEulerAnglesXYZ(euler) // Angles are in radians
// Convert to degrees
val pitchDegrees = Math.toDegrees(euler.x.toDouble()) // Rotation around X axis = pitch
val yawDegrees = Math.toDegrees(euler.y.toDouble()) // Rotation around Y axis = yaw
val rollDegrees = Math.toDegrees(euler.z.toDouble()) // Rotation around Z axis = roll
//Scale rotation delta by 20 to represent degree per second instead of tick
angDelta = Vec3(pitchDegrees, yawDegrees, rollDegrees).scale(20.0)
/******************************************************
* Calculate ride local velocity
*****************************************************/
val velocityWorldF = Vector3f(currentVelocity.x.toFloat(), currentVelocity.y.toFloat(), currentVelocity.z.toFloat())
val localVelocityF = Matrix3f(orientation).transpose().transform(velocityWorldF)
val localVelocity = Vec3(localVelocityF.x.toDouble(), localVelocityF.y.toDouble(), localVelocityF.z.toDouble())
localVelocitySpring.update(localVelocity, stiffness, damping)
// Update previous values
prevOrientation.set(currOrientation)
} else {
val currPitch = entity.xRot
val currYaw = entity.yRot
val currRoll = 0.0f
currRot = Vec3(currPitch.toDouble(), currYaw.toDouble(), currRoll.toDouble())
//Scale rotation delta by 20 to represent degree per second instead of tick
angDelta = Vec3(
(currRot.x - prevRot.x),
Mth.degreesDifference(currRot.y.toFloat(), prevRot.y.toFloat()).toDouble(),
Mth.degreesDifference(currRot.z.toFloat(), prevRot.z.toFloat()).toDouble()
).scale(20.0)
/******************************************************
* Calculate ride local velocity
*****************************************************/
val yaw360 = -1.0 * (entity.yRot + 360.0f) % 360.0f
val orientationNonRollable = Matrix3f().rotateY(yaw360.toRadians())
//Convert to Vector3f
var velocityWorldF = Vector3f(currentVelocity.x.toFloat(), currentVelocity.y.toFloat(), currentVelocity.z.toFloat())
val localVelocityF = Matrix3f(orientationNonRollable).transpose().transform(velocityWorldF)
val localVelocity = Vec3(localVelocityF.x.toDouble(), localVelocityF.y.toDouble(), localVelocityF.z.toDouble())
localVelocitySpring.update(localVelocity, stiffness, damping)
}
/******************************************************
* Update springs
*****************************************************/
rotDeltaSpring.update(angDelta, stiffness, damping)
velocitySpring.update(currentVelocity, stiffness, damping)
rotSpring.update(currRot, stiffness, damping)
prevRot = currRot
}
}
@@ -0,0 +1,68 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding.util
import net.minecraft.world.phys.Vec3
import kotlin.math.min
/**
* A spring-based smoother for Vec3 values, designed for applying damped spring motion to riding data.
* Stores the previous and current values, along with a history buffer for lookback-based interpolation.
*
* @author Jackowes
* @since March 27th, 2025
*/
class Vec3Spring(
var value: Vec3 = Vec3.ZERO,
var velocity: Vec3 = Vec3.ZERO
) {
val history = ArrayDeque<Vec3>()
//Hold up to a seconds worth of values
val lookBackSize = 20
fun update(target: Vec3, stiffness: Double, damping: Double) {
//Hooke's Law f = kx where:
//f is force
//k is the spring constant or stiffness of this spring
//x is the distance from rest and in this case the difference between the most recent
//rotation delta ( the target ) and the springs current value for delta rot
val force = target.subtract(value).scale(stiffness)
//Now calculate acceleration and apply damping
val accel = force.subtract(velocity.scale(damping))
velocity = velocity.add(accel.scale(1.0/20.0))
value = value.add(velocity.scale(1.0/20.0))
history.addFirst(value)
//Adding one since if we want to check max look back point it needs something to interp with.
if( history.size > lookBackSize + 1) {
history.removeLast()
}
}
fun getInterpolated(partialTick: Double, lookBackTick: Int): Vec3 {
if (history.size < 2) {
return value // or Vec3.ZERO if you prefer
}
val tick = min(lookBackTick, history.size - 2)
var ret = Vec3.ZERO
for( i in 0..tick) {
val older = history.get(i + 1).scale(1.0)
val newer = history.get(i).scale(1.0)
ret = ret.add(older.add(newer.subtract(older).scale(partialTick)))
}
return ret.scale(1.0/(tick+1))
}
}
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory
import com.cobblemon.mod.common.platform.events.PlatformEvents
import com.cobblemon.mod.common.util.server
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
import net.minecraft.server.level.ServerLevel
import java.util.UUID
import net.minecraft.server.level.ServerPlayer
@@ -32,24 +33,45 @@ object CobblemonWorldSpawnerManager : SpawnerManager() {
init {
PlatformEvents.SERVER_PLAYER_LOGIN.subscribe { this.onPlayerLogin(it.player) }
PlatformEvents.SERVER_PLAYER_LOGOUT.subscribe { this.onPlayerLogout(it.player) }
PlatformEvents.CHANGE_DIMENSION.subscribe { this.onDimensionChange(it.player, it.origin, it.destination) }
}
fun onPlayerLogin(player: ServerPlayer) {
// Disables spawning
if (!Cobblemon.config.enableSpawning || server()?.gameRules?.getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING) == false) {
if (!Cobblemon.config.enableSpawning || player.level().gameRules.getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING) == false) {
return;
}
val spawner = PlayerSpawnerFactory.create(this, player)
spawnersForPlayers[player.uuid] = spawner
registerSpawner(spawner)
registerPlayerSpawner(player)
}
fun onPlayerLogout(player: ServerPlayer) {
val spawner = spawnersForPlayers[player.uuid]
if (spawner != null) {
spawnersForPlayers.remove(player.uuid)
unregisterSpawner(spawner)
unregisterPlayerSpawner(player)
}
fun onDimensionChange(player: ServerPlayer, origin: ServerLevel?, destination: ServerLevel?) {
fun getSpawnRule(level: ServerLevel?) = level?.gameRules?.getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING)
if (!Cobblemon.config.enableSpawning || getSpawnRule(origin) == getSpawnRule(destination)) {
return
}
val spawnerAction = if (destination?.gameRules?.getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING) == false) {
::unregisterPlayerSpawner
} else {
::registerPlayerSpawner
}
spawnerAction(player)
}
private fun unregisterPlayerSpawner(player: ServerPlayer) {
spawnersForPlayers.remove(player.uuid)?.let { unregisterSpawner(it) }
}
private fun registerPlayerSpawner(player: ServerPlayer) {
PlayerSpawnerFactory.create(this, player).also {
spawnersForPlayers[player.uuid] = it
registerSpawner(it)
}
}
}
@@ -71,10 +71,15 @@ open class SpawnerManager {
open fun onServerTick() {
// Disables spawning
if (!Cobblemon.config.enableSpawning || server()?.gameRules?.getBoolean(DO_POKEMON_SPAWNING) == false) {
if (!Cobblemon.config.enableSpawning) {
return
}
influences.removeIf { it.isExpired() }
getSpawnersOfType<TickingSpawner>().forEach(TickingSpawner::tick)
getSpawnersOfType<TickingSpawner>().forEach {
if (it.getCauseEntity()?.level()?.gameRules?.getBoolean(DO_POKEMON_SPAWNING) == false) {
return@forEach
}
it.tick()
}
}
}
@@ -0,0 +1,133 @@
/*
* 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 com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.block.entity.StadiumBlockEntity
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.InteractionResult
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.BaseEntityBlock
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.HorizontalDirectionalBlock
import net.minecraft.world.level.block.Mirror
import net.minecraft.world.level.block.RenderShape
import net.minecraft.world.level.block.Rotation
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.phys.BlockHitResult
class StadiumBlock(properties: Properties): BaseEntityBlock(properties) {
companion object {
val CODEC = simpleCodec(::StadiumBlock)
}
init {
registerDefaultState(stateDefinition.any().setValue(HorizontalDirectionalBlock.FACING, Direction.NORTH))
}
override fun codec() = CODEC
override fun newBlockEntity(pos: BlockPos, state: BlockState): BlockEntity {
return StadiumBlockEntity(pos, state)
}
override fun getStateForPlacement(blockPlaceContext: BlockPlaceContext): BlockState {
return this.defaultBlockState().setValue(HorizontalDirectionalBlock.FACING, blockPlaceContext.horizontalDirection)
}
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
builder.add(HorizontalDirectionalBlock.FACING)
}
override fun rotate(blockState: BlockState, rotation: Rotation): BlockState {
return blockState.setValue(
HorizontalDirectionalBlock.FACING, rotation.rotate(blockState.getValue(
HorizontalDirectionalBlock.FACING)))
}
override fun mirror(blockState: BlockState, mirror: Mirror): BlockState {
return blockState.rotate(mirror.getRotation(blockState.getValue(HorizontalDirectionalBlock.FACING)))
}
override fun onRemove(state: BlockState, world: Level, pos: BlockPos, newState: BlockState, moved: Boolean) {
if (!state.`is`(newState.block)) super.onRemove(state, world, pos, newState, moved)
}
//TODO: override getTicker
override fun getRenderShape(state: BlockState) = RenderShape.MODEL
override fun useWithoutItem(
state: BlockState,
world: Level,
pos: BlockPos,
player: Player,
hitResult: BlockHitResult
): InteractionResult {
if (player !is ServerPlayer) return InteractionResult.SUCCESS
val blockEntity = world.getBlockEntity(pos)
if (blockEntity !is StadiumBlockEntity) return InteractionResult.SUCCESS
player.sendSystemMessage(text("Adding you to Battle").red())
blockEntity.addPlayer(player)
return InteractionResult.SUCCESS
}
/*
override fun useWithoutItem(
blockState: BlockState,
world: Level,
blockPos: BlockPos,
player: Player,
blockHitResult: BlockHitResult
): InteractionResult {
if (player !is ServerPlayer) return InteractionResult.SUCCESS
val blockEntity = world.getBlockEntity(blockPos)
if (blockEntity !is StadiumBlockEntity) return InteractionResult.SUCCESS
// Toggle isInUse state
blockEntity.isInUse = !blockEntity.isInUse
// debug
val activateMessage = if (blockEntity.isInUse) "Stadium Activated!" else "Stadium Deactivated!"
player.sendSystemMessage(text(activateMessage).red())
if (blockEntity.isInUse) {
// Generate flight path when activated
blockEntity.generateFlightPath(world, radiusX = 5.0, radiusZ = 3.0, height = 10.0, steps = 20)
} else {
// Clear path when deactivated
blockEntity.pathPoints.clear()
}
val message = "Stadium Pos: " + blockEntity.blockPos +
"\nPlayer 1 Pos: " + blockEntity.getPlayer1Pos() +
"\nPoke 1 Pos: " + blockEntity.getPoke1Pos() +
"\nPlayer 2 Pos: " + blockEntity.getPlayer2Pos() +
"\nPoke 2 Pos: " + blockEntity.getPoke2Pos()
player.sendSystemMessage(text(message).red())
blockEntity.setChanged()
world.sendBlockUpdated(blockPos, blockState, blockState, Block.UPDATE_CLIENTS)
return InteractionResult.SUCCESS
}
*/
}
@@ -0,0 +1,143 @@
package com.cobblemon.mod.common.block.entity
import com.cobblemon.mod.common.CobblemonBlockEntities
import com.cobblemon.mod.common.client.render.models.blockbench.drone.DroneState
import com.cobblemon.mod.common.stadium.StadiumSingleBattle
import net.minecraft.core.BlockPos
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.network.protocol.Packet
import net.minecraft.network.protocol.game.ClientGamePacketListener
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket
import net.minecraft.network.protocol.game.ClientboundPlayerLookAtPacket
import net.minecraft.network.protocol.game.ClientboundSetCarriedItemPacket
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.Vec3
class StadiumBlockEntity(
pos: BlockPos,
blockState: BlockState
): BlockEntity(
CobblemonBlockEntities.STADIUM,
pos,
blockState
) {
var storedPlayers = mutableListOf<ServerPlayer>()
var battleDefenition = StadiumSingleBattle()
fun addPlayer(player: ServerPlayer) {
battleDefenition.addPlayer(player)
if (battleDefenition.readyForBattle()) battleDefenition.initializeBattle()
}
/*
var isInUse = false
val droneState = DroneState()
val pathPoints: MutableList<Vec3> = mutableListOf()
fun generateFlightPath(world: Level, radiusX: Double, radiusZ: Double, height: Double, steps: Int) {
pathPoints.clear()
for (i in 0 until steps) {
val angle = (i.toDouble() / steps) * Math.PI * 2
val xOffset = radiusX * Math.cos(angle)
val zOffset = radiusZ * Math.sin(angle)
val basePos = Vec3(blockPos.x + xOffset, blockPos.y + height, blockPos.z + zOffset)
val adjustedPos = getValidPoint(world, basePos)
pathPoints.add(adjustedPos)
}
}
private fun getValidPoint(world: Level, start: Vec3): Vec3 {
val maxHeight = 40 // Max height for drone path
val stepHeight = 1.0 // Step size for raycast
var adjustedHeight = start.y
for (h in 0..maxHeight step stepHeight.toInt()) {
val checkPos = BlockPos(start.x.toInt(), start.y.toInt() - h, start.z.toInt()) // Convert to BlockPos
if (!world.getBlockState(checkPos).isAir) { // Check if block is solid
return Vec3(start.x, start.y - h - 1, start.z) // Adjust position
}
}
return start // No obstruction found
}
fun getPlayer1Pos(): BlockPos {
return blockPos.north(10)
}
fun getPlayer2Pos(): BlockPos {
return blockPos.south(10)
}
fun getPoke1Pos(): BlockPos {
return blockPos.north(5)
}
fun getPoke2Pos(): BlockPos {
return blockPos.south(5)
}
/**
* Saves data to NBT.
*/
override fun saveAdditional(tag: CompoundTag, registries: HolderLookup.Provider) {
super.saveAdditional(tag, registries)
// Save the isInUse state
tag.putBoolean("IsInUse", isInUse)
// Save path points
val pathTag = ListTag()
for (point in pathPoints) {
val pointTag = CompoundTag()
pointTag.putDouble("x", point.x)
pointTag.putDouble("y", point.y)
pointTag.putDouble("z", point.z)
pathTag.add(pointTag)
}
tag.put("PathPoints", pathTag)
}
/**
* Loads data from NBT.
*/
override fun loadAdditional(tag: CompoundTag, registries: HolderLookup.Provider) {
super.loadAdditional(tag, registries)
// Load the isInUse state
isInUse = tag.getBoolean("IsInUse")
// Load path points
pathPoints.clear()
val pathTag = tag.getList("PathPoints", 10) // 10 is the ID for CompoundTag
for (i in 0 until pathTag.size) {
val pointTag = pathTag.getCompound(i)
val point = Vec3(pointTag.getDouble("x"), pointTag.getDouble("y"), pointTag.getDouble("z"))
pathPoints.add(point)
}
}
override fun getUpdatePacket(): Packet<ClientGamePacketListener>? {
//println("getUpdatePacket called for NestBlockEntity at $blockPos with egg: $eggComponent")
return ClientboundBlockEntityDataPacket.create(this)
}
override fun getUpdateTag(registryLookup: HolderLookup.Provider): CompoundTag {
val tag = saveWithoutMetadata(registryLookup)
//println("getUpdateTag called for NestBlockEntity at $blockPos with tag: $tag")
return tag
}
*/
}
@@ -26,13 +26,7 @@ import com.cobblemon.mod.common.client.gui.battle.BattleOverlay
import com.cobblemon.mod.common.client.particle.BedrockParticleOptionsRepository
import com.cobblemon.mod.common.client.render.ClientPlayerIcon
import com.cobblemon.mod.common.client.render.DeferredRenderer
import com.cobblemon.mod.common.client.render.block.BerryBlockRenderer
import com.cobblemon.mod.common.client.render.block.DisplayCaseRenderer
import com.cobblemon.mod.common.client.render.block.FossilAnalyzerRenderer
import com.cobblemon.mod.common.client.render.block.GildedChestBlockRenderer
import com.cobblemon.mod.common.client.render.block.HealingMachineRenderer
import com.cobblemon.mod.common.client.render.block.LecternBlockEntityRenderer
import com.cobblemon.mod.common.client.render.block.RestorationTankRenderer
import com.cobblemon.mod.common.client.render.block.*
import com.cobblemon.mod.common.client.render.boat.CobblemonBoatRenderer
import com.cobblemon.mod.common.client.render.entity.PokeBobberEntityRenderer
import com.cobblemon.mod.common.client.render.generic.GenericBedrockRenderer
@@ -60,6 +54,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.stadium.StadiumClientManager
import com.cobblemon.mod.common.util.isLookingAt
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
@@ -116,6 +111,7 @@ object CobblemonClient {
CobblemonDataProvider.canReload = true
DeferredRenderer.clearAll()
ClientPlayerIcon.clear()
StadiumClientManager.onLogout()
}
fun initialize(implementation: CobblemonClientImplementation) {
@@ -260,7 +256,8 @@ object CobblemonClient {
CobblemonBlocks.SKY_TUMBLESTONE_CLUSTER,
CobblemonBlocks.GIMMIGHOUL_CHEST,
CobblemonBlocks.DISPLAY_CASE,
CobblemonBlocks.LECTERN
CobblemonBlocks.LECTERN,
CobblemonBlocks.STADIUM
)
this.createBoatModelLayers()
@@ -294,6 +291,7 @@ object CobblemonClient {
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.GILDED_CHEST, ::GildedChestBlockRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.DISPLAY_CASE, ::DisplayCaseRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.LECTERN, ::LecternBlockEntityRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.STADIUM, ::StadiumBlockRenderer)
}
private fun registerEntityRenderers() {
@@ -458,10 +458,11 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
formRightButton.render(context,mouseX, mouseY, delta)
val form = showableForms[selectedFormIndex]
val formName = if (form.displayForm.lowercase() == "normal") "" else "-${form.displayForm.lowercase().replace("-", "")}"
drawScaledTextJustifiedRight(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = lang("ui.pokedex.info.form.${form.displayForm.lowercase()}").bold(),
text = lang("ui.pokedex.info.form.${species}${formName}").bold(),
x = pX + 136,
y = pY + 15,
shadow = true
@@ -0,0 +1,209 @@
/*
* 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.block
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.block.entity.StadiumBlockEntity
import com.cobblemon.mod.common.client.render.models.blockbench.drone.DroneModel
import com.cobblemon.mod.common.client.render.models.blockbench.drone.DroneState
import com.cobblemon.mod.common.client.render.models.blockbench.repository.RenderContext
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository
import com.cobblemon.mod.common.util.cobblemonResource
import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.math.Axis
import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.RenderType
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider
import net.minecraft.client.renderer.texture.OverlayTexture
import net.minecraft.core.Direction
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.level.block.HorizontalDirectionalBlock
import net.minecraft.world.level.block.state.BlockState
class StadiumBlockRenderer(ctx: BlockEntityRendererProvider.Context) : BlockEntityRenderer<StadiumBlockEntity> {
val context = RenderContext().also {
it.put(RenderContext.DO_QUIRKS, false)
it.put(RenderContext.RENDER_STATE, RenderContext.RenderState.BLOCK)
}
private var pathIndex = 0
private var animationTime = 0.0
private val droneSpeed = 0.10
override fun render(
blockEntity: StadiumBlockEntity,
partialTick: Float,
poseStack: PoseStack,
bufferSource: MultiBufferSource,
packedLight: Int,
packedOverlay: Int
) {
}
/*
override fun render(
blockEntity: StadiumBlockEntity,
tickDelta: Float,
poseStack: PoseStack,
multiBufferSource: MultiBufferSource,
light: Int,
overlay: Int
) {
val blockState = blockEntity.blockState
val yRot = blockState.getValue(HorizontalDirectionalBlock.FACING).toYRot()
val isClientSide = blockEntity.level?.isClientSide == true
if (!isClientSide) return
val stadiumBlockState = blockEntity.level?.getBlockState(blockEntity.blockPos) ?: return
if (stadiumBlockState.block != CobblemonBlocks.STADIUM) {
return
}
val droneState = blockEntity.droneState
poseStack.pushPose()
if (blockEntity.isInUse) {
if (blockEntity.pathPoints.isEmpty()) {
poseStack.popPose()
return
}
spawnDebugParticles(blockEntity) // debug particles
// Center the drone at the block's center
poseStack.translate(0.5, -3.0, 0.5)
//poseStack.mulPose(Axis.XP.rotationDegrees(180F))
//poseStack.mulPose(Axis.YP.rotationDegrees(180F))
val points = blockEntity.pathPoints
val nextIndex = (pathIndex + 1) % points.size
val currentPoint = points[pathIndex]
val nextPoint = points[nextIndex]
animationTime += tickDelta * droneSpeed
if (animationTime >= 1.0) {
animationTime = 0.0
pathIndex = nextIndex
}
val interpolatedPos = currentPoint.lerp(nextPoint, animationTime.toDouble())
println("DEBUG: Drone moving between points:")
println(" - Current Point: ${currentPoint}")
println(" - Next Point: ${nextPoint}")
println(" - Interpolated Position: $interpolatedPos")
poseStack.translate(interpolatedPos.x - blockEntity.blockPos.x,
interpolatedPos.y - blockEntity.blockPos.y,
interpolatedPos.z - blockEntity.blockPos.z)
println("DEBUG: Drone position interpolated to: $interpolatedPos")
poseStack.mulPose(Axis.YP.rotationDegrees(-yRot))
poseStack.mulPose(Axis.ZP.rotationDegrees(180F)) // flip the drone right side up
renderDrone(droneState, "sleep", tickDelta, poseStack, 1.0F, multiBufferSource, light)
} else {
val yRot = blockState.getValue(HorizontalDirectionalBlock.FACING).toYRot()
val poseEntry = poseStack.last()
val matrix = poseEntry.pose()
poseStack.translate(0.5, 0.0, 0.5)
poseStack.mulPose(Axis.YP.rotationDegrees(yRot))
val posX = matrix.m03()
val posY = matrix.m13()
val posZ = matrix.m23()
println("DEBUG: Drone is NOT in use. Rendering default position at: x=$posX, y=$posY, z=$posZ")
poseStack.mulPose(Axis.ZP.rotationDegrees(180F))
renderDrone(droneState, "sleep", tickDelta, poseStack, 1.0F, multiBufferSource, light)
}
poseStack.popPose()
}
fun renderDrone(
state: DroneState,
pose: String,
tickDelta: Float,
poseStack: PoseStack,
scale: Float = 1F,
multiBufferSource: MultiBufferSource,
light: Int,
) {
state.updatePartialTicks(tickDelta)
val droneResource: ResourceLocation = cobblemonResource("rotom_drone")
val model = VaryingModelRepository.getPoser(droneResource, state) as DroneModel
val texture = VaryingModelRepository.getTexture(droneResource, state)
val buffer = multiBufferSource.getBuffer(RenderType.entityCutout(texture))
model.bufferProvider = multiBufferSource
state.currentModel = model
state.setPose(pose)
model.context = context
context.put(RenderContext.TEXTURE, texture)
context.put(RenderContext.RENDER_STATE, RenderContext.RenderState.BLOCK)
context.put(RenderContext.POSABLE_STATE, state)
model.applyAnimations(
entity = null,
state = state,
headYaw = 0F,
headPitch = 0F,
limbSwing = 0F,
limbSwingAmount = 0F,
ageInTicks = state.animationSeconds * 20
)
poseStack.scale(scale, scale, scale)
// TODO: Make drone lighting dynamic (simply using the light arg makes the drone always appear dark)
model.withLayerContext(multiBufferSource, state, VaryingModelRepository.getLayers(droneResource, state)) {
model.render(context, poseStack, buffer, 200, OverlayTexture.NO_OVERLAY, -0x1)
}
model.setDefault()
}
private fun spawnDebugParticles(blockEntity: StadiumBlockEntity) {
val world = blockEntity.level ?: return
if (!world.isClientSide) return // Only run on the client-side
for (point in blockEntity.pathPoints) {
world.addParticle(
net.minecraft.core.particles.ParticleTypes.FLAME, // Test particle (changeable)
point.x, point.y, point.z, // Position of the particle
0.0, 0.02, 0.0 // Slight upward motion
)
}
// Spawn a special particle at the next interpolation point
if (blockEntity.pathPoints.isNotEmpty()) {
val nextPoint = blockEntity.pathPoints[(pathIndex + 1) % blockEntity.pathPoints.size]
world.addParticle(
net.minecraft.core.particles.ParticleTypes.END_ROD, // Different effect for next point
nextPoint.x, nextPoint.y, nextPoint.z,
0.0, 0.05, 0.0
)
}
}
*/
}
@@ -35,6 +35,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.quirk.ModelQuirk
import com.cobblemon.mod.common.client.render.models.blockbench.quirk.QuirkData
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.mojang.brigadier.StringReader
import com.mojang.brigadier.exceptions.CommandSyntaxException
@@ -101,7 +102,8 @@ abstract class PosableState : Schedulable {
val allActiveAnimations: List<ActiveAnimation> get() = activeAnimations + quirks.flatMap { it.value.animations }
/** The tick-driven age of the state. Combines with [currentPartialTicks] to produce the animation seconds. */
protected var age = 0
var age = 0
protected set
/**
* The partial tick value of the state. Combines with [age] to produce the animation seconds. For entity-based state
* this will be consistently reset to a new value, whereas non-entity-based state will increment this value.
@@ -131,8 +133,137 @@ abstract class PosableState : Schedulable {
/** A list of items to be rendered on a PosableModel during an animation */
val animationItems = mutableMapOf<String, ItemStack>()
/** All of the MoLang functions that can be expose current riding data. */
val ridingFunctions = QueryStruct(hashMapOf())
.addFunction("pitch") { params ->
val lookBackTick = params.getInt(0)
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
val partialTickPitch = pokemon.ridingAnimationData.rotSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).x
val maxPitch = 90.0
return@addFunction DoubleValue((partialTickPitch / maxPitch).coerceIn(-1.0,1.0))
}
.addFunction("yaw") { params ->
val lookBackTick = params.getInt(0)
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
val partialTickYaw = pokemon.ridingAnimationData.rotSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).y
val maxYaw = 180.0
return@addFunction DoubleValue((partialTickYaw / maxYaw).coerceIn(-1.0,1.0))
}
.addFunction("roll") { params ->
val lookBackTick = params.getInt(0)
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
val partialTickRoll = pokemon.ridingAnimationData.rotSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).z
val maxRoll = 180.0
return@addFunction DoubleValue((partialTickRoll / maxRoll).coerceIn(-1.0,1.0))
}
.addFunction("pitch_change") { params ->
val lookBackTick = params.getInt(0)
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
val partialTickPitchDelta = pokemon.ridingAnimationData.rotDeltaSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).x
//TODO: hook back up the retrieval of the current behaviors stat for this and the following functions
val maxRotRate = 140.0//pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SKILL)
//?: return@addFunction DoubleValue(0.0)
return@addFunction DoubleValue((partialTickPitchDelta / maxRotRate).coerceIn(-1.0,1.0))
}
.addFunction("yaw_change") { params ->
val lookBackTick = params.getInt(0)
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
val partialTickYawDelta = pokemon.ridingAnimationData.rotDeltaSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).y
//TODO: make this not hardcoded
val maxRotRate = 140.0 //pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SKILL)
//?: return@addFunction DoubleValue(0.0)
return@addFunction DoubleValue((partialTickYawDelta / maxRotRate).coerceIn(-1.0,1.0))
}
.addFunction("roll_change") { params ->
val lookBackTick = params.getInt(0)
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
val partialTickRollDelta = pokemon.ridingAnimationData.rotDeltaSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).z
val maxRotRate = 140.0 //pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SKILL)
//?: return@addFunction DoubleValue(0.0)
return@addFunction DoubleValue((partialTickRollDelta / maxRotRate).coerceIn(-1.0,1.0))
}
.addFunction("speed") { params ->
val lookBackTick = params.getInt(0)
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
val partialTickSpeed = pokemon.ridingAnimationData.velocitySpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).length()
val topSpeed = 1.0//pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SPEED)
//?: return@addFunction DoubleValue(0.0)
return@addFunction DoubleValue((partialTickSpeed / topSpeed).coerceIn(-1.0,1.0))
}
.addFunction("velocity_x") { params ->
val lookBackTick = params.getInt(0)
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
val partialTickXVel = pokemon.ridingAnimationData.velocitySpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).x
val topSpeed = 1.0//pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SPEED)
//?: return@addFunction DoubleValue(0.0)
return@addFunction DoubleValue((partialTickXVel / topSpeed).coerceIn(-1.0,1.0))
}
.addFunction("velocity_y") { params ->
val lookBackTick = params.getInt(0)
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
val partialTickYVel = pokemon.ridingAnimationData.velocitySpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).y
val topSpeed = 1.0//pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SPEED)
//?: return@addFunction DoubleValue(0.0)
return@addFunction DoubleValue((partialTickYVel / topSpeed).coerceIn(-1.0,1.0))
}
.addFunction("velocity_z") { params ->
val lookBackTick = params.getInt(0)
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
val partialTickZVel = pokemon.ridingAnimationData.velocitySpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).z
val topSpeed = 1.0//pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SPEED)
//?: return@addFunction DoubleValue(0.0)
return@addFunction DoubleValue((partialTickZVel / topSpeed).coerceIn(-1.0,1.0))
}
.addFunction("velocity_right") { params ->
val lookBackTick = params.getInt(0)
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
val partialTickZVel = pokemon.ridingAnimationData.localVelocitySpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).x
val topSpeed = 1.0//pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SPEED)
//?: return@addFunction DoubleValue(0.0)
return@addFunction DoubleValue((partialTickZVel / topSpeed).coerceIn(-1.0,1.0) * -1.0)
}
.addFunction("velocity_upward") { params ->
val lookBackTick = params.getInt(0)
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
val partialTickZVel = pokemon.ridingAnimationData.localVelocitySpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).y
val topSpeed = 1.0//pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SPEED)
//?: return@addFunction DoubleValue(0.0)
return@addFunction DoubleValue((partialTickZVel / topSpeed).coerceIn(-1.0,1.0))
}
.addFunction("velocity_forward") { params ->
val lookBackTick = params.getInt(0)
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
val partialTickZVel = pokemon.ridingAnimationData.localVelocitySpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).z
val topSpeed = 1.0//pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SPEED)
//?: return@addFunction DoubleValue(0.0)
return@addFunction DoubleValue((partialTickZVel / topSpeed).coerceIn(-1.0,1.0))
}
/** All of the MoLang functions that can be applied to something with this state. */
val functions = QueryStruct(hashMapOf())
val functions = QueryStruct(hashMapOf(
"riding" to java.util.function.Function { ridingFunctions },
"r" to java.util.function.Function { ridingFunctions }
))
.addFunction("anim_time") {
reusableAnimTime.value = animationSeconds.toDouble()
reusableAnimTime
@@ -432,4 +563,4 @@ abstract class PosableState : Schedulable {
1F
}
}
}
}
@@ -198,9 +198,11 @@ data class BedrockAnimation(
boneTimelines.forEach { (boneName, timeline) ->
val part = relevantPartsByName[boneName] ?: if (boneName == "root_part") (rootPart as? ModelPart) else null
val isCamera = boneName == "locator_camera"
val scalar = if (isCamera) 1.0 else intensity.toDouble()
if (part !== null) {
if (!timeline.position.isEmpty()) {
val position = timeline.position.resolve(animationSeconds.toDouble(), runtime).scale(intensity.toDouble())
val position = timeline.position.resolve(animationSeconds.toDouble(), runtime).scale(scalar)
part.apply {
x += position.x.toFloat()
y += position.y.toFloat()
@@ -210,7 +212,7 @@ data class BedrockAnimation(
if (!timeline.rotation.isEmpty()) {
try {
val rotation = timeline.rotation.resolve(animationSeconds.toDouble(), runtime).scale(intensity.toDouble())
val rotation = timeline.rotation.resolve(animationSeconds.toDouble(), runtime).scale(scalar)
part.apply {
xRot += rotation.x.toFloat().toRadians()
yRot += rotation.y.toFloat().toRadians()
@@ -230,14 +232,14 @@ data class BedrockAnimation(
if (!timeline.scale.isEmpty()) {
var scale = timeline.scale.resolve(animationSeconds.toDouble(), runtime)
// If the goal is to make the invisible then kick that into gear after 0.5. Maybe could work better somehow else.
if (scale == Vec3.ZERO && intensity > 0.5) {
if (scale == Vec3.ZERO && scalar > 0.5) {
part.xScale *= scale.x.toFloat()
part.yScale *= scale.y.toFloat()
part.zScale *= scale.z.toFloat()
} else {
// The deviation from 1 is what we want to multiply by the intensity of the animation.
val deviation = scale.scale(-1.0).add(1.0, 1.0, 1.0)
val weakenedDeviation = deviation.scale(intensity.toDouble())
val weakenedDeviation = deviation.scale(scalar)
scale = weakenedDeviation.subtract(1.0, 1.0, 1.0).scale(-1.0)
part.xScale *= scale.x.toFloat()
part.yScale *= scale.y.toFloat()
@@ -394,4 +396,4 @@ enum class InterpolationType {
enum class Transformation {
POSITION, ROTATION, SCALE
}
}
@@ -0,0 +1,39 @@
/*
* Copyright (C) 2025 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.drone
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.animation.PoseAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Bone
import com.cobblemon.mod.common.client.render.models.blockbench.quirk.ModelQuirk
import com.cobblemon.mod.common.entity.PoseType
import com.google.gson.annotations.SerializedName
import net.minecraft.client.model.geom.ModelPart
/**
* A model for rendering the Rotom drone used by the stadium block.
*
* @author Flarkinater
* @since February 14th, 2025
*/
class DroneModel(root: Bone) : PosableModel(root) {
@Transient
@SerializedName("So this name can be literally anything, huh?")
override val rootPart = (root as ModelPart).registerChildWithAllChildren(root.children.entries.first().key)
var droneAnimations: Array<PoseAnimation> = emptyArray()
var droneQuirks: Array<ModelQuirk<*>> = emptyArray()
override fun registerPoses() {
registerPose(
poseType = PoseType.SLEEP,
animations = droneAnimations,
quirks = droneQuirks
)
}
}
@@ -0,0 +1,34 @@
/*
* Copyright (C) 2025 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.drone
import com.cobblemon.mod.common.api.scheduling.SchedulingTracker
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
/**
* State for a drone Rotom attached to a stadium block.
*
* @author Flarkinater
* @since February 12th, 2025
*/
class DroneState() : PosableState() {
init {
setPose("sleep")
age = 0
currentPartialTicks = 0F
}
override fun getEntity() = null
override fun updatePartialTicks(partialTicks: Float) {
currentPartialTicks += partialTicks / 2
}
override val schedulingTracker = SchedulingTracker()
}
@@ -1,64 +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.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
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.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class KangaskhanModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
override val rootPart = root.registerChildWithAllChildren("kangaskhan")
override val head = getPart("head")
override var portraitScale = 1.7F
override var portraitTranslation = Vec3(-0.15, 1.1, 0.0)
override var profileScale = 0.7F
override var profileTranslation = Vec3(0.0, 0.65, 0.0)
lateinit var standing: Pose
lateinit var walk: Pose
override fun registerPoses() {
val blink = quirk { bedrockStateful("kangaskhan", "blink")}
val blink2 = quirk { bedrockStateful("kangaskhan", "blink2")}
standing = registerPose(
poseName = "standing",
poseTypes = STATIONARY_POSES + UI_POSES,
transformTicks = 10,
quirks = arrayOf(blink, blink2),
animations = arrayOf(
singleBoneLook(),
bedrock("kangaskhan", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
transformTicks = 10,
quirks = arrayOf(blink, blink2),
animations = arrayOf(
singleBoneLook(),
bedrock("kangaskhan", "ground_idle")
//bedrock("kangaskhan", "ground_walk")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PosableState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("kangaskhan", "faint") else null
}
@@ -1,76 +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.gen7
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.QuadrupedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class MudsdaleModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, QuadrupedFrame {
override val rootPart = root.registerChildWithAllChildren("mudsdale")
override val head = getPart("neck")
override val foreLeftLeg = getPart("leg_front_left")
override val foreRightLeg = getPart("leg_front_right")
override val hindLeftLeg = getPart("leg_back_left")
override val hindRightLeg = getPart("leg_back_right")
override var portraitScale = 1.5F
override var portraitTranslation = Vec3(-1.0, 1.76, 0.0)
override var profileScale = 0.5F
override var profileTranslation = Vec3(0.0, 1.0, 0.0)
lateinit var standing: Pose
lateinit var walk: Pose
lateinit var sleep: Pose
override val cryAnimation = CryProvider { bedrockStateful("mudsdale", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("mudsdale", "blink") }
sleep = registerPose(
poseType = PoseType.SLEEP,
animations = arrayOf(bedrock("mudsdale", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(disableY = true),
bedrock("mudsdale", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(disableY = true),
bedrock("mudsdale", "ground_walk")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PosableState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("mudsdale", "faint") else null
}
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.*
import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animation.BedrockAnimationRepository
import com.cobblemon.mod.common.client.render.models.blockbench.blockentity.BlockEntityModel
import com.cobblemon.mod.common.client.render.models.blockbench.fossil.FossilModel
import com.cobblemon.mod.common.client.render.models.blockbench.drone.DroneModel
import com.cobblemon.mod.common.client.render.models.blockbench.pokeball.AncientPokeBallModel
import com.cobblemon.mod.common.client.render.models.blockbench.pokeball.BeastBallModel
import com.cobblemon.mod.common.client.render.models.blockbench.pokeball.PokeBallModel
@@ -79,12 +80,14 @@ object VaryingModelRepository {
"poke_balls",
"generic",
"block_entities",
"drone"
)
val poserDirectories: List<Pair<String, Class<out PosableModel>>> = listOf(
"bedrock/posers" to PosableModel::class.java,
"bedrock/pokemon/posers" to PokemonPosableModel::class.java,
"bedrock/fossils/posers" to FossilModel::class.java,
"bedrock/drone/posers" to DroneModel::class.java,
"bedrock/block_entities/posers" to BlockEntityModel::class.java,
"bedrock/npcs/posers" to PosableModel::class.java,
"bedrock/poke_balls/posers" to PosableModel::class.java,
@@ -116,6 +119,7 @@ object VaryingModelRepository {
.registerTypeAdapter(PosableModel::class.java, JsonModelAdapter(::PosableModel))
.registerTypeAdapter(PokemonPosableModel::class.java, JsonModelAdapter(::PokemonPosableModel))
.registerTypeAdapter(FossilModel::class.java, JsonModelAdapter(::FossilModel))
.registerTypeAdapter(DroneModel::class.java, JsonModelAdapter(::DroneModel))
.registerTypeAdapter(BlockEntityModel::class.java, JsonModelAdapter(::BlockEntityModel))
.registerTypeAdapter(Pose::class.java, PoseAdapter { JsonModelAdapter.model!! })
.registerTypeAdapter(ModelPartTransformation::class.java, ModelPartTransformationAdapter)
@@ -287,7 +291,6 @@ object VaryingModelRepository {
inbuilt("kabuto", ::KabutoModel)
inbuilt("kabutops", ::KabutopsModel)
inbuilt("kadabra", ::KadabraModel)
inbuilt("kangaskhan", ::KangaskhanModel)
inbuilt("koffing", ::KoffingModel)
inbuilt("krabby", ::KrabbyModel)
inbuilt("lickitung", ::LickitungModel)
@@ -481,7 +484,6 @@ object VaryingModelRepository {
inbuilt("taillow", ::TaillowModel)
inbuilt("swellow", ::SwellowModel)
inbuilt("mudbray", ::MudbrayModel)
inbuilt("mudsdale", ::MudsdaleModel)
inbuilt("comfey", ::ComfeyModel)
inbuilt("tandemaus", ::TandemausModel)
inbuilt("maushold", ::MausholdModel)
@@ -49,6 +49,8 @@ import com.cobblemon.mod.common.net.messages.client.data.UnlockReloadPacket
import com.cobblemon.mod.common.platform.events.PlatformEvents
import com.cobblemon.mod.common.pokemon.SpeciesAdditions
import com.cobblemon.mod.common.pokemon.properties.PropertiesCompletionProvider
import com.cobblemon.mod.common.stadium.StadiumCameraManagers
import com.cobblemon.mod.common.stadium.StadiumCameras
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.ifClient
import com.cobblemon.mod.common.util.server
@@ -97,6 +99,8 @@ object CobblemonDataProvider : DataProvider {
this.register(CobblemonCosmeticItems)
this.register(CobblemonFlows)
this.register(CobblemonUnlockableWallpapers)
this.register(StadiumCameras)
this.register(StadiumCameraManagers)
this.register(Marks)
CobblemonSpawnPools.load()
@@ -49,6 +49,8 @@ import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviours
import com.cobblemon.mod.common.api.riding.events.SelectDriverEvent
import com.cobblemon.mod.common.api.riding.stats.RidingStat
import com.cobblemon.mod.common.api.riding.util.RidingAnimationData
import com.cobblemon.mod.common.api.riding.util.Vec3Spring
import com.cobblemon.mod.common.api.scheduling.Schedulable
import com.cobblemon.mod.common.api.scheduling.SchedulingTracker
import com.cobblemon.mod.common.api.scheduling.afterOnServer
@@ -251,6 +253,7 @@ open class PokemonEntity(
var enablePoseTypeRecalculation = true
val ridingAnimationData: RidingAnimationData = RidingAnimationData()
var previousRidingState: RidingBehaviourState? = null
var ridingState: RidingBehaviourState? = null
@@ -483,6 +486,11 @@ open class PokemonEntity(
entityData.get(MOVING)
super.tick()
if (passengers.isNotEmpty()) {
ridingAnimationData.update(this)
}
flyDistO = flyDist
if (isBattling) {
@@ -1565,6 +1573,8 @@ open class PokemonEntity(
inp.z * g.toDouble() + inp.x * f.toDouble()
)
val diff = v.subtract(this.deltaMovement)
val inertia = ifRidingAvailableSupply(fallback = 0.5) { behaviour, settings, state ->
@@ -1924,7 +1934,7 @@ open class PokemonEntity(
// }
override fun onPassengerTurned(entityToUpdate: Entity) {
if (entityToUpdate !is LivingEntity) return
if (entityToUpdate !is LivingEntity) return
ifRidingAvailable { behaviour, settings, state ->
behaviour.clampPassengerRotation(settings, state, this, entityToUpdate)
}
@@ -1942,6 +1952,22 @@ open class PokemonEntity(
}
}
// When riding mimic RemotePlayers logic for rendering players at farther
// distances than usual. Otherwise the player may render when the pokemon
// entity is not, causing a floating player.
override fun shouldRenderAtSqrDistance(distance: Double): Boolean {
if (!passengers.isEmpty()) {
var d = (boundingBox.getSize() * 10.0)
if (d.isNaN()) {
d = 1.0
}
val scale = 64.0 * getViewScale()
return distance < d * scale * scale
}
return super.shouldRenderAtSqrDistance(distance)
}
override fun getControllingPassenger(): LivingEntity? {
val riders = this.passengers.filterIsInstance<LivingEntity>()
if (riders.isEmpty()) {
@@ -238,6 +238,7 @@ object CobblemonItemGroups {
entries.accept(CobblemonItems.PC)
entries.accept(CobblemonItems.HEALING_MACHINE)
entries.accept(CobblemonItems.PASTURE)
entries.accept(CobblemonItems.STADIUM)
entries.accept(CobblemonItems.GILDED_CHEST)
entries.accept(CobblemonItems.YELLOW_GILDED_CHEST)
@@ -353,6 +354,18 @@ object CobblemonItemGroups {
entries.accept(CobblemonItems.LEEK_AND_POTATO_STEW)
entries.accept(CobblemonItems.BRAISED_VIVICHOKE)
entries.accept(CobblemonItems.VIVICHOKE_DIP)
entries.accept(CobblemonItems.TART_APPLE)
entries.accept(CobblemonItems.SWEET_APPLE)
entries.accept(CobblemonItems.SYRUPY_APPLE)
entries.accept(CobblemonItems.WHIPPED_DREAM)
entries.accept(CobblemonItems.STRAWBERRY_SWEET)
entries.accept(CobblemonItems.LOVE_SWEET)
entries.accept(CobblemonItems.BERRY_SWEET)
entries.accept(CobblemonItems.CLOVER_SWEET)
entries.accept(CobblemonItems.FLOWER_SWEET)
entries.accept(CobblemonItems.STAR_SWEET)
entries.accept(CobblemonItems.RIBBON_SWEET)
entries.accept(CobblemonItems.BERRY_JUICE)
entries.accept(CobblemonItems.REMEDY)
entries.accept(CobblemonItems.FINE_REMEDY)
@@ -475,6 +488,7 @@ object CobblemonItemGroups {
entries.accept(CobblemonItems.WHIPPED_DREAM)
entries.accept(CobblemonItems.TART_APPLE)
entries.accept(CobblemonItems.SWEET_APPLE)
entries.accept(CobblemonItems.SYRUPY_APPLE)
entries.accept(CobblemonItems.CRACKED_POT)
entries.accept(CobblemonItems.CHIPPED_POT)
entries.accept(CobblemonItems.MASTERPIECE_TEACUP)
@@ -644,9 +658,23 @@ object CobblemonItemGroups {
}
private fun foodInjections(injector: Injector) {
injector.putAfter(CobblemonItems.TART_APPLE, Items.ENCHANTED_GOLDEN_APPLE)
injector.putAfter(CobblemonItems.SWEET_APPLE, CobblemonItems.TART_APPLE)
injector.putAfter(CobblemonItems.SYRUPY_APPLE, CobblemonItems.SWEET_APPLE)
injector.putAfter(CobblemonItems.MEDICINAL_LEEK, Items.POISONOUS_POTATO)
injector.putAfter(CobblemonItems.ROASTED_LEEK, CobblemonItems.MEDICINAL_LEEK)
injector.putAfter(CobblemonItems.BRAISED_VIVICHOKE, CobblemonItems.ROASTED_LEEK)
injector.putAfter(CobblemonItems.WHIPPED_DREAM, Items.PUMPKIN_PIE)
injector.putAfter(CobblemonItems.STRAWBERRY_SWEET, CobblemonItems.WHIPPED_DREAM)
injector.putAfter(CobblemonItems.LOVE_SWEET, CobblemonItems.STRAWBERRY_SWEET)
injector.putAfter(CobblemonItems.BERRY_SWEET, CobblemonItems.LOVE_SWEET)
injector.putAfter(CobblemonItems.CLOVER_SWEET, CobblemonItems.BERRY_SWEET)
injector.putAfter(CobblemonItems.FLOWER_SWEET, CobblemonItems.CLOVER_SWEET)
injector.putAfter(CobblemonItems.STAR_SWEET, CobblemonItems.FLOWER_SWEET)
injector.putAfter(CobblemonItems.RIBBON_SWEET, CobblemonItems.STAR_SWEET)
injector.putAfter(CobblemonItems.LEEK_AND_POTATO_STEW, Items.RABBIT_STEW)
injector.putAfter(CobblemonItems.VIVICHOKE_DIP, CobblemonItems.LEEK_AND_POTATO_STEW)
}
@@ -10,10 +10,17 @@ package com.cobblemon.mod.common.item.interactive
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.item.PokemonSelectingItem
import com.cobblemon.mod.common.api.molang.ObjectValue
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
import com.cobblemon.mod.common.client.render.models.blockbench.animation.PrimaryAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animation.BedrockActiveAnimation
import com.cobblemon.mod.common.item.CobblemonItem
import com.cobblemon.mod.common.pokemon.Nature
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.lang
import com.cobblemon.mod.common.stadium.StadiumClientManager
import com.cobblemon.mod.common.stadium.deserialize
import com.cobblemon.mod.common.util.*
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.server.level.ServerPlayer
@@ -45,9 +52,21 @@ class MintItem(val nature: Nature) : CobblemonItem(Properties()), PokemonSelecti
}
override fun use(world: Level, user: Player, hand: InteractionHand): InteractionResultHolder<ItemStack> {
if (user is ServerPlayer) {
return use(user, user.getItemInHand(hand))
// if (user is ServerPlayer) {
// return use(user, user.getItemInHand(hand))
// }
if (!world.isClientSide) return InteractionResultHolder.fail(user.getItemInHand(hand))
val pokemon = CobblemonClient.storage.myParty.first { it?.entity != null } ?: return InteractionResultHolder.fail(user.getItemInHand(hand))
val entity = pokemon.entity ?: return InteractionResultHolder.fail(user.getItemInHand(hand))
val delegate = entity.delegate as? PokemonClientDelegate ?: return InteractionResultHolder.fail(user.getItemInHand(hand))
val bedrockAnimation = when (pokemon.species.name) {
"Tinkaton" -> (delegate.runtime.resolve("q.bedrock_primary('tinkaton', 'signature')".asExpression()).value() as ObjectValue<*>).obj as PrimaryAnimation
"Tandemaus" -> (delegate.runtime.resolve("q.bedrock_primary('tandemaus', 'faint')".asExpression()).value() as ObjectValue<*>).obj as PrimaryAnimation
else -> (delegate.runtime.resolve("q.bedrock_primary('ceruledge', 'battle_cry')".asExpression()).value() as ObjectValue<*>).obj as PrimaryAnimation
}
delegate.addPrimaryAnimation(bedrockAnimation)
StadiumClientManager.playAnimation(entity, bedrockAnimation)
return InteractionResultHolder.success(user.getItemInHand(hand))
}
}
}
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.platform.events
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
class ChangeDimensionEvent(val player: ServerPlayer)
class ChangeDimensionEvent(val player: ServerPlayer, val origin: ServerLevel?, val destination: ServerLevel?)
@@ -0,0 +1,32 @@
package com.cobblemon.mod.common.stadium
import com.cobblemon.mod.common.util.adapters.Vec3dAdapter
import com.google.gson.GsonBuilder
import net.minecraft.world.phys.Vec3
import org.joml.Vector3f
val gson = GsonBuilder()
.setPrettyPrinting()
.disableHtmlEscaping()
.registerTypeAdapter(Vec3::class.java, Vec3dAdapter)
.create()
fun deserialize(data: String): CameraAnimation {
return gson.fromJson(data, CameraAnimation::class.java)
}
data class CameraAnimation(
val length: Double,
val origin: CameraOrigin,
val timeline: Timeline
)
data class Timeline(
val position: Map<Double, Vec3>,
val rotation: Map<Double, Vec3>,
)
data class CameraOrigin(
val position: Vec3,
val rotation: Vec3,
)
@@ -0,0 +1,25 @@
package com.cobblemon.mod.common.stadium
import net.minecraft.server.level.ServerPlayer
import java.util.*
abstract class StadiumBattleDefenition {
var stadiumBattleID: UUID = UUID.randomUUID()
var participants: MutableList<UUID> = mutableListOf<UUID>()
var spectators: MutableList<UUID> = mutableListOf<UUID>()
var cameras: MutableList<StadiumCameraEntry> = mutableListOf<StadiumCameraEntry>()
abstract fun readyForBattle(): Boolean
abstract fun canAddPlayer(player: ServerPlayer): Boolean
abstract fun addPlayer(player: ServerPlayer)
abstract fun getPlayers(): MutableList<ServerPlayer>
abstract fun initializeBattle()
abstract fun getCurrentCamera(): StadiumCameraEntry
}
@@ -0,0 +1,192 @@
package com.cobblemon.mod.common.stadium
import com.bedrockk.molang.Expression
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.util.*
import com.google.gson.JsonArray
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import net.fabricmc.loader.impl.lib.sat4j.core.Vec
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.phys.Vec3
import org.joml.Vector3f
import java.lang.reflect.Type
import kotlin.math.abs
import kotlin.math.atan
import kotlin.math.atan2
class StadiumCameraEntry(
var id: ResourceLocation,
val length: Double = 0.0,
val positionTimeline: MutableMap<String, CameraKeyFrame> = mutableMapOf(),
val targetPositionTimeline: MutableMap<String, CameraKeyFrame> = mutableMapOf(),
val move: String = ""
) {
fun resolvePosition(time: Double): Vec3 {
return resolvePosition(time, positionTimeline)
}
private fun resolvePosition(time: Double, map: MutableMap<String, CameraKeyFrame>): Vec3 {
val runtime = StadiumClientManager.runtime
runtime.environment.setSimpleVariable("anim_time", DoubleValue(time))
var frame1: CameraKeyFrame? = null
var frame2: CameraKeyFrame? = null
var time1 = -1.0
var time2 = -1.0
for (keyframe in map) {
if (time >= keyframe.key.toDouble()) {
if (time1 == -1.0 || abs(time - keyframe.key.toDouble()) < abs(time - time1)) {
frame1 = keyframe.value
time1 = keyframe.key.toDouble()
}
}
if (time < keyframe.key.toDouble()) {
if (time2 == -1.0 || abs(time - keyframe.key.toDouble()) < abs(time - time2)) {
frame2 = keyframe.value
time2 = keyframe.key.toDouble()
}
}
}
val difference = (time - time1) / (time2 - time1)
if (frame1 != null && frame1.interpolation == CameraInterpolation.STEP) {
frame2 = null
}
if (frame1 == null && frame2 == null) {
return Vec3.ZERO
}
else if (frame1 == null) {
frame2!!
val x = runtime.resolveDouble(frame2.x)
val y = runtime.resolveDouble(frame2.y)
val z = runtime.resolveDouble(frame2.z)
return Vec3(x,y,z)
}
else if (frame2 == null) {
val x = runtime.resolveDouble(frame1.x)
val y = runtime.resolveDouble(frame1.y)
val z = runtime.resolveDouble(frame1.z)
return Vec3(x,y,z)
}
else {
val x1 = runtime.resolveDouble(frame1.x)
val y1 = runtime.resolveDouble(frame1.y)
val z1 = runtime.resolveDouble(frame1.z)
val vec1 = Vec3(x1,y1,z1)
val x2 = runtime.resolveDouble(frame2.x)
val y2 = runtime.resolveDouble(frame2.y)
val z2 = runtime.resolveDouble(frame2.z)
val vec2 = Vec3(x2,y2,z2)
return vec1.lerp(vec2, difference)
}
}
fun resolveRotation(time: Double): Vector3f {
val position = resolvePosition(time, positionTimeline)
val target = resolvePosition(time, targetPositionTimeline)
val offset = target.subtract(position)
val xRot = -atan(offset.y.toFloat()/offset.horizontalDistance().toFloat()) * (180F / Math.PI.toFloat())
val yRot = -atan2(offset.x.toFloat(),offset.z.toFloat()) * (180F / Math.PI.toFloat())
return Vector3f(xRot, yRot, 0.0F)
}
fun encode(buf: RegistryFriendlyByteBuf) {
buf.writeIdentifier(id)
buf.writeDouble(length)
buf.writeMap(positionTimeline, {_, key -> buf.writeString(key)}, {_, value ->
buf.writeString(value.x.getString())
buf.writeString(value.y.getString())
buf.writeString(value.z.getString())
buf.writeEnum(value.interpolation)
})
buf.writeMap(targetPositionTimeline, {_, key -> buf.writeString(key)}, {_, value ->
buf.writeString(value.x.getString())
buf.writeString(value.y.getString())
buf.writeString(value.z.getString())
buf.writeEnum(value.interpolation)
})
buf.writeString(move)
}
companion object {
fun decode(buf: RegistryFriendlyByteBuf) : StadiumCameraEntry {
val id = buf.readIdentifier()
val length = buf.readDouble()
val positionTimeline = buf.readMap({_ -> buf.readString()}, {_ ->
CameraKeyFrame(buf.readString().asExpression(), buf.readString().asExpression(), buf.readString().asExpression(), buf.readEnum(CameraInterpolation::class.java))
}).toMutableMap()
val targetPositionTimeline = buf.readMap({_ -> buf.readString()}, {_ ->
CameraKeyFrame(buf.readString().asExpression(), buf.readString().asExpression(), buf.readString().asExpression(), buf.readEnum(CameraInterpolation::class.java))
}).toMutableMap()
val move = buf.readString()
return StadiumCameraEntry(id, length, positionTimeline, targetPositionTimeline, move)
}
}
data class CameraKeyFrame (
val x: Expression,
val y: Expression,
val z: Expression,
val interpolation: CameraInterpolation
)
enum class CameraInterpolation {
LINEAR,
STEP
}
object CameraEntryAdapter: JsonDeserializer<StadiumCameraEntry> {
override fun deserialize(
json: JsonElement?,
typeOfT: Type?,
context: JsonDeserializationContext?
): StadiumCameraEntry {
if (json is JsonObject) {
val length = json["length"]?.asDouble ?: 0.0
val positionTimeline = mutableMapOf<String, CameraKeyFrame>()
json["positions"]?.asJsonObject?.entrySet()?.forEach { (name, position) ->
val xyz = position.asJsonObject["xyz"]
var x = "0.0".asExpression()
var y = "0.0".asExpression()
var z = "0.0".asExpression()
if (xyz != null && xyz.isJsonArray && xyz.asJsonArray.size() == 3) {
x = xyz.asJsonArray[0].asString.asExpression()
y = xyz.asJsonArray[1].asString.asExpression()
z = xyz.asJsonArray[2].asString.asExpression()
}
val interpolation = when (position.asJsonObject["interpolation"]?.asString) {
"linear" -> CameraInterpolation.LINEAR
"step" -> CameraInterpolation.STEP
else -> CameraInterpolation.LINEAR
}
positionTimeline[name] = CameraKeyFrame(x, y, z, interpolation)
}
val targetPositionTimeline = mutableMapOf<String, CameraKeyFrame>()
json["targetPositions"]?.asJsonObject?.entrySet()?.forEach { (name, position) ->
val xyz = position.asJsonObject["xyz"]
var x = "0.0".asExpression()
var y = "0.0".asExpression()
var z = "0.0".asExpression()
if (xyz != null && xyz.isJsonArray && xyz.asJsonArray.size() == 3) {
x = xyz.asJsonArray[0].asString.asExpression()
y = xyz.asJsonArray[1].asString.asExpression()
z = xyz.asJsonArray[2].asString.asExpression()
}
val interpolation = when (position.asJsonObject["interpolation"]?.asString) {
"linear" -> CameraInterpolation.LINEAR
"step" -> CameraInterpolation.STEP
else -> CameraInterpolation.LINEAR
}
targetPositionTimeline[name] = CameraKeyFrame(x, y, z, interpolation)
}
val move = json["move"]?.asString ?: ""
}
throw IllegalStateException("Stadium Camera could not be parsed")
}
}
}
@@ -0,0 +1,119 @@
package com.cobblemon.mod.common.stadium
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.util.*
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import java.lang.reflect.Type
class StadiumCameraManagerEntry(
var id: ResourceLocation,
val states: MutableMap<String, StadiumCameraState>,
val startingState: String
) {
fun encode(buf: RegistryFriendlyByteBuf) {
buf.writeIdentifier(id)
buf.writeMap(states, {_, key -> buf.writeString(key)}, {_, value -> value.encode(buf)})
buf.writeString(startingState)
}
companion object {
fun decode(buf: RegistryFriendlyByteBuf): StadiumCameraManagerEntry {
val id = buf.readIdentifier()
val states = buf.readMap({buf.readString()}, {StadiumCameraState.decode(buf)}).toMutableMap()
val startState = buf.readString()
return StadiumCameraManagerEntry(id, states, startState)
}
}
}
class StadiumCameraState(
val camera: Expression,
val target: StadiumCameraTarget,
val listOfTransitions: MutableList<StadiumCameraTransition>,
val loop: Boolean
) {
fun encode(buf: RegistryFriendlyByteBuf) {
buf.writeString(camera.originalString)
buf.writeEnum(target)
buf.writeCollection(listOfTransitions) {_, transition -> transition.encode(buf)}
buf.writeBoolean(loop)
}
companion object {
fun decode(buf: RegistryFriendlyByteBuf): StadiumCameraState {
val camera = buf.readString().asExpression()
val target = buf.readEnum(StadiumCameraTarget::class.java)
val listOfTransitions = buf.readList { StadiumCameraTransition.decode(buf) }.toMutableList()
val loop = buf.readBoolean()
return StadiumCameraState(camera, target, listOfTransitions, loop)
}
}
}
class StadiumCameraTransition(
val targetState: String,
val checkOnEnd: Boolean,
val condition: Expression
) {
fun encode(buf: RegistryFriendlyByteBuf) {
buf.writeString(targetState)
buf.writeBoolean(checkOnEnd)
buf.writeString(condition.originalString)
}
companion object {
fun decode(buf: RegistryFriendlyByteBuf): StadiumCameraTransition {
val targetState = buf.readString()
val checkOnEnd = buf.readBoolean()
val condition = buf.readString().asExpression()
return StadiumCameraTransition(targetState, checkOnEnd, condition)
}
}
}
enum class StadiumCameraTarget {
CENTRE,
ACTIVE_POKEMON,
ENEMY_POKEMON,
TRAINER
}
object StadiumCameraManagerAdapter: JsonDeserializer<StadiumCameraManagerEntry> {
override fun deserialize(
json: JsonElement?,
typeOfT: Type?,
context: JsonDeserializationContext?
): StadiumCameraManagerEntry {
if (json is JsonObject) {
val states = mutableMapOf<String, StadiumCameraState>()
json["states"]?.asJsonObject?.entrySet()?.forEach { (name, state) ->
val camera = state.asJsonObject["camera"]?.asString?.asExpression() ?: "".asExpression()
val target = when (state.asJsonObject["target"]?.asString) {
"CENTRE" -> StadiumCameraTarget.CENTRE
"ACTIVE_POKEMON" -> StadiumCameraTarget.ACTIVE_POKEMON
"ENEMY_POKEMON" -> StadiumCameraTarget.ENEMY_POKEMON
"TRAINER" -> StadiumCameraTarget.TRAINER
else -> StadiumCameraTarget.CENTRE
}
val listOfTransitions = mutableListOf<StadiumCameraTransition>()
state.asJsonObject["transitions"]?.asJsonArray?.forEach {
val targetState = it.asJsonObject["targetState"]?.asString ?: ""
val checkOnEnd = it.asJsonObject["checkOnEnd"]?.asBoolean ?: false
val condition = it.asJsonObject["condition"]?.asString?.asExpression() ?: "0.0".asExpression()
listOfTransitions.add(StadiumCameraTransition(targetState, checkOnEnd, condition))
}
val loop = state.asJsonObject["loop"]?.asBoolean ?: false
states[name] = StadiumCameraState(camera, target, listOfTransitions, loop)
}
val startingState = json["startingState"].asString ?: ""
return StadiumCameraManagerEntry(cobblemonResource(""), states, startingState)
}
throw IllegalStateException("StadiumCameraManager could not be parsed")
}
}
@@ -0,0 +1,46 @@
package com.cobblemon.mod.common.stadium
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
object StadiumCameraManagers: JsonDataRegistry<StadiumCameraManagerEntry> {
override val id = cobblemonResource("stadium_managers")
override val type = PackType.SERVER_DATA
override val gson: Gson = GsonBuilder()
.disableHtmlEscaping()
.setPrettyPrinting()
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.registerTypeAdapter(StadiumCameraManagerEntry::class.java, StadiumCameraManagerAdapter)
.create()
override val typeToken: TypeToken<StadiumCameraManagerEntry> = TypeToken.get(StadiumCameraManagerEntry::class.java)
override val resourcePath = "stadium_managers"
val managers = mutableMapOf<ResourceLocation, StadiumCameraManagerEntry>()
override fun reload(data: Map<ResourceLocation, StadiumCameraManagerEntry>) {
managers.clear()
data.forEach { location, manager ->
manager.id = location
managers[location] = manager
}
observable.emit(this)
}
override val observable = SimpleObservable<StadiumCameraManagers>()
override fun sync(player: ServerPlayer) {
StadiumCameraManagersSyncPacket(managers.values).sendToPlayer(player)
}
}
@@ -0,0 +1,27 @@
package com.cobblemon.mod.common.stadium
import com.cobblemon.mod.common.net.messages.client.data.DataRegistrySyncPacket
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.RegistryFriendlyByteBuf
class StadiumCameraManagersSyncPacket(managers: Collection<StadiumCameraManagerEntry>) :
DataRegistrySyncPacket<StadiumCameraManagerEntry, StadiumCameraManagersSyncPacket>(managers) {
override fun encodeEntry(buffer: RegistryFriendlyByteBuf, entry: StadiumCameraManagerEntry) {
entry.encode(buffer)
}
override fun decodeEntry(buffer: RegistryFriendlyByteBuf): StadiumCameraManagerEntry? {
return StadiumCameraManagerEntry.decode(buffer)
}
override fun synchronizeDecoded(entries: Collection<StadiumCameraManagerEntry>) {
StadiumCameraManagers.reload(entries.associateBy { it.id })
}
override val id = ID
companion object {
val ID = cobblemonResource("stadium_camera_managers_sync")
fun decode(buffer: RegistryFriendlyByteBuf) = StadiumCameraManagersSyncPacket(emptyList()).apply { decodeBuffer(buffer) }
}
}
@@ -0,0 +1,48 @@
package com.cobblemon.mod.common.stadium
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
object StadiumCameras: JsonDataRegistry<StadiumCameraEntry> {
override val id = cobblemonResource("stadium_cameras")
override val type = PackType.SERVER_DATA
override val gson: Gson = GsonBuilder()
.disableHtmlEscaping()
.setPrettyPrinting()
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.registerTypeAdapter(StadiumCameraEntry::class.java, StadiumCameraEntry.CameraEntryAdapter)
.create()
override val typeToken: TypeToken<StadiumCameraEntry> = TypeToken.get(StadiumCameraEntry::class.java)
override val resourcePath = "stadium_cameras"
val cameras = mutableMapOf<ResourceLocation, StadiumCameraEntry>()
override fun reload(data: Map<ResourceLocation, StadiumCameraEntry>) {
cameras.clear()
data.forEach { location, camera ->
camera.id = location
cameras[location] = camera
}
observable.emit(this)
}
override val observable = SimpleObservable<StadiumCameras>()
override fun sync(player: ServerPlayer) {
StadiumCamerasSyncPacket(cameras.values).sendToPlayer(player)
}
fun getMoveCamera(move: String): StadiumCameraEntry? {
return cameras.values.firstOrNull { it.move == move }
}
}
@@ -0,0 +1,27 @@
package com.cobblemon.mod.common.stadium
import com.cobblemon.mod.common.net.messages.client.data.DataRegistrySyncPacket
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.RegistryFriendlyByteBuf
class StadiumCamerasSyncPacket(cameras: Collection<StadiumCameraEntry>) :
DataRegistrySyncPacket<StadiumCameraEntry, StadiumCamerasSyncPacket>(cameras) {
override fun encodeEntry(buffer: RegistryFriendlyByteBuf, entry: StadiumCameraEntry) {
entry.encode(buffer)
}
override fun decodeEntry(buffer: RegistryFriendlyByteBuf): StadiumCameraEntry? {
return StadiumCameraEntry.decode(buffer)
}
override fun synchronizeDecoded(entries: Collection<StadiumCameraEntry>) {
StadiumCameras.reload(entries.associateBy { it.id })
}
override val id = ID
companion object {
val ID = cobblemonResource("stadium_cameras_sync")
fun decode(buffer: RegistryFriendlyByteBuf) = StadiumCamerasSyncPacket(emptyList()).apply { decodeBuffer(buffer) }
}
}
@@ -0,0 +1,232 @@
package com.cobblemon.mod.common.stadium
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.MoValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.client.ClientMoLangFunctions.setupClient
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.MountedPokemonAnimationRenderController
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
import com.cobblemon.mod.common.client.render.models.blockbench.animation.PrimaryAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animation.linearLerpAlpha
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.asResource
import com.cobblemon.mod.common.util.math.fromEulerXYZ
import com.cobblemon.mod.common.util.math.geometry.toRadians
import com.cobblemon.mod.common.util.math.toEulerXYZ
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.resolveString
import com.cobblemon.mod.common.util.toVec3d
import net.minecraft.resources.ResourceLocation
import net.minecraft.util.Mth
import net.minecraft.world.phys.Vec3
import org.joml.Matrix4f
import org.joml.Quaternionf
import org.joml.Vector3f
import java.util.*
import java.util.function.Function
import com.cobblemon.mod.common.util.plus
import net.minecraft.client.Minecraft
object StadiumClientManager {
//Molang
fun MoLangRuntime.setupCameraFunctions(): MoLangRuntime {
environment.query.addFunctions(
hashMapOf(
"moveCamera" to Function { params ->
if (params.get<MoValue>(0) !is StringValue) {
return@Function Unit
}
val camera = StadiumCameras.getMoveCamera(params.get<MoValue>(0).asString())
return@Function camera?.id?.toString() ?: ""
}
)
)
return this
}
val runtime = MoLangRuntime().setup().setupClient().setupCameraFunctions()
var currentStadiumBattleUUID: UUID? = null
var Instruction = "DEFAULT"
var InstructionChangeTime = 0.0
var InstructionJustChanged = false
fun updateState(newState: String) {
Instruction = newState
InstructionChangeTime = 0.0
InstructionJustChanged = true
}
fun onLogout() {
currentStadiumBattleUUID = null
}
fun handleJoin(battleUUID: UUID, cameraManager: ResourceLocation) {
currentStadiumBattleUUID = battleUUID
activeCameraManager = cameraManager
cameraTimer = 0.0
currentCameraState = StadiumCameraManagers.managers[cameraManager]!!.startingState
cameraPosition = Vec3.ZERO
cameraRotation = Quaternionf()
updateCameraData(0.0)
}
fun inStadiumBattle(): Boolean {
return currentStadiumBattleUUID != null
}
fun shouldUseStadiumCamera(): Boolean {
return animation != null
}
//Molang Data
fun updateMolangVar() {
val environment = runtime.environment
environment.setSimpleVariable("instruction", StringValue(Instruction))
//environment.setSimpleVariable("instructionChangeTime", DoubleValue(InstructionChangeTime))
environment.setSimpleVariable("instructionJustChanged", DoubleValue(InstructionJustChanged))
val isSpectating = CobblemonClient.battle?.spectating ?: false
environment.setSimpleVariable("isBattling", DoubleValue(!isSpectating))
environment.setSimpleVariable("isSpectating", DoubleValue(isSpectating))
}
fun instructionUpdate(newState: String, additionalValues: MutableMap<String, MoValue>) {
val environment = runtime.environment
Instruction = newState
InstructionChangeTime = 0.0
InstructionJustChanged = true
for (value in additionalValues) {
environment.setSimpleVariable(value.key, value.value)
}
}
//Camera Manager
var activeCameraManager: ResourceLocation? = null
var cameraTimer: Double = 0.0
var currentCameraState: String = ""
var nextCameraState: String = ""
var calculateNextState: Boolean = true
fun tickCameraManager() {
if (!shouldUseStadiumCamera()) return
//Molang Variables
val environment = runtime.environment
if (CobblemonClient.battle != null) {
environment.setSimpleVariable("selectingMove", DoubleValue(CobblemonClient.battle!!.mustChoose))
}
else {
environment.setSimpleVariable("selectingMove", DoubleValue(0.0))
}
val currentManager = StadiumCameraManagers.managers[activeCameraManager]!!
val currentState = currentManager.states[currentCameraState]!!
val currentCamera = StadiumCameras.cameras[runtime.resolveString(currentState.camera).asResource()]
InstructionChangeTime += 0.05
if (currentCamera != null) {
cameraTimer += 0.05
if (cameraTimer > currentCamera.length) {
if (currentState.loop) {
cameraTimer -= currentCamera.length
}
else {
cameraTimer = currentCamera.length
}
}
}
if (!calculateNextState) {
currentCameraState = nextCameraState
calculateNextState = true
cameraTimer = if (currentCamera != null && currentCamera.length != 0.0) cameraTimer - currentCamera.length else 0.0
}
else {
updateMolangVar()
environment.setSimpleVariable("instructionChangeTime", DoubleValue(InstructionChangeTime))
val endOfAnim = if (currentCamera != null) cameraTimer + 1/20 >= currentCamera.length else true
val nextState = evaluateTransitions(currentState, endOfAnim)
if (nextState != null) {
nextCameraState = nextState.targetState
while (true) {
val newState = currentManager.states[nextCameraState]!!
val newCamera = StadiumCameras.cameras[runtime.resolveString(newState.camera).asResource()]
val newEndOfAnim = if (newCamera != null) newCamera.length == 0.0 else true
val newNextState = evaluateTransitions(newState, newEndOfAnim)
if (newNextState == null) {
break
}
else {
nextCameraState = newNextState.targetState
}
}
calculateNextState = false
}
}
if (InstructionJustChanged) {
InstructionJustChanged = false
Instruction = "NONE"
}
}
private fun evaluateTransitions(state: StadiumCameraState, checkEnd: Boolean) : StadiumCameraTransition? {
var nextState = state.listOfTransitions.firstOrNull { !it.checkOnEnd && runtime.resolveBoolean(it.condition) }
if (nextState == null && checkEnd) {
nextState = state.listOfTransitions.firstOrNull { it.checkOnEnd && runtime.resolveBoolean(it.condition) }
}
return nextState
}
var cameraPosition: Vec3 = Vec3.ZERO
var cameraRotation: Quaternionf = Quaternionf()
var startTime = 0.0
var startPosition: Vec3? = null
var startRotation: Vector3f? = null
var attackAnimationPokemon: PokemonEntity? = null
var animation: PrimaryAnimation? = null
var oldFov: Int = 0
fun playAnimation(pokemon: PokemonEntity, animation: PrimaryAnimation) {
if (startTime != 0.0) return
attackAnimationPokemon = pokemon
this.animation = animation
this.oldFov = Minecraft.getInstance().options.fov().get()
animation.afterAction += {
cameraPosition = Vec3.ZERO
cameraRotation = Quaternionf()
attackAnimationPokemon = null
this.animation = null
Minecraft.getInstance().options.fov().set(oldFov)
}
}
fun updateCameraData(delta: Double) {
val pokemon = attackAnimationPokemon ?: return
val delegate = pokemon.delegate as? PokemonClientDelegate ?: return
delegate.updatePartialTicks(delta.toFloat())
MountedPokemonAnimationRenderController.reset()
MountedPokemonAnimationRenderController.setup(pokemon, delta.toFloat())
val locator = delegate.locatorStates["camera"] ?: return
cameraPosition = locator.position.add(locator.matrix.getTranslation(Vector3f()).toVec3d())
cameraRotation = locator.matrix.getUnnormalizedRotation(Quaternionf()).normalize()
val cameraPart = delegate.currentModel?.getPart("locator_camera") ?: return
val fov = cameraPart.zScale.toInt()
if (Minecraft.getInstance().options.fov().get() != fov) {
Minecraft.getInstance().options.fov().set(fov)
}
}
}
@@ -0,0 +1,4 @@
package com.cobblemon.mod.common.stadium
class StadiumFormat {
}
@@ -0,0 +1,13 @@
package com.cobblemon.mod.common.stadium
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
import net.minecraft.client.Minecraft
import net.minecraft.server.MinecraftServer
import net.minecraft.server.level.ServerPlayer
object StadiumJoinHandler: ClientNetworkPacketHandler<StadiumJoinPacket> {
override fun handle(packet: StadiumJoinPacket, client: Minecraft) {
StadiumClientManager.handleJoin(packet.joiningBattle, packet.cameraManager)
}
}
@@ -0,0 +1,24 @@
package com.cobblemon.mod.common.stadium
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.readIdentifier
import com.cobblemon.mod.common.util.writeIdentifier
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import java.util.*
class StadiumJoinPacket(
val joiningBattle: UUID,
val cameraManager: ResourceLocation
): NetworkPacket<StadiumJoinPacket> {
override val id = ID
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeUUID(this.joiningBattle)
buffer.writeIdentifier(cameraManager)
}
companion object {
val ID = cobblemonResource("stadium_join")
fun decode(buffer: RegistryFriendlyByteBuf) = StadiumJoinPacket(buffer.readUUID(), buffer.readIdentifier())
}
}
@@ -0,0 +1,34 @@
package com.cobblemon.mod.common.stadium
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import java.util.UUID
object StadiumServerManager {
val activeStadiumBattles = mutableMapOf<UUID, StadiumBattleInstance>()
fun createNewStadiumBattle(battle: UUID, managerResource: ResourceLocation, participants: MutableList<UUID> = mutableListOf<UUID>()) {
val newInstance = StadiumBattleInstance(battle, managerResource)
newInstance.participants = participants
activeStadiumBattles[battle] = newInstance
}
fun terminateNewStadiumBattle(battle: UUID) {
activeStadiumBattles.remove(battle)
}
fun addPlayerToStadiumBattle(battle: UUID, player: UUID) {
val instance = activeStadiumBattles[battle]
if (instance != null) {
if (!instance.participants.contains(player)) instance.participants.add(player)
}
}
}
class StadiumBattleInstance(
val stadiumBattleId: UUID,
val managerResource: ResourceLocation
){
var participants = mutableListOf<UUID>()
}
@@ -0,0 +1,63 @@
package com.cobblemon.mod.common.stadium
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.battles.BattleBuilder
import com.cobblemon.mod.common.battles.SuccessfulBattleStart
import com.cobblemon.mod.common.util.getPlayer
import com.cobblemon.mod.common.util.party
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.phys.Vec3
class StadiumSingleBattle: StadiumBattleDefenition() {
@JvmField
val MAX_PLAYERS = 2
var player1Position = Vec3(0.0,0.0,0.0)
var player2Position = Vec3(0.0,0.0,0.0)
var player1PokemonPosition = Vec3(0.0,0.0,0.0)
var player2PokemonPosition = Vec3(0.0,0.0,0.0)
var activeBattle: PokemonBattle? = null
override fun readyForBattle(): Boolean {
return this.getPlayers().count() == MAX_PLAYERS
}
override fun canAddPlayer(player: ServerPlayer): Boolean {
val party = player.party()
return party.occupied() > 0
}
override fun addPlayer(player: ServerPlayer) {
if (canAddPlayer(player)) {
participants.add(player.uuid)
player.sendPacket(StadiumJoinPacket(player.uuid, StadiumCameraManagers.managers.keys.first()))
}
}
override fun getPlayers(): MutableList<ServerPlayer> {
return participants.mapNotNull { it.getPlayer() }.toMutableList()
}
override fun initializeBattle() {
if (!readyForBattle()) return
val players = getPlayers()
val player1 = players[0]
val player2 = players[1]
val battleResult = BattleBuilder.pvp1v1(player1, player2)
var errored = false
battleResult.ifErrored { errored = true }
if (errored) return
val battle = (battleResult as SuccessfulBattleStart).battle
}
override fun getCurrentCamera(): StadiumCameraEntry {
TODO("Not yet implemented")
}
}
@@ -0,0 +1,15 @@
package com.cobblemon.mod.common.util
import com.cobblemon.mod.common.util.math.geometry.toDegrees
import com.cobblemon.mod.common.util.math.toEulerXYZ
import net.minecraft.client.Camera
import org.joml.Quaternionf
fun Camera.setRotation(pitch: Float, yaw: Float, roll: Float) {
this.xRot = pitch.toDegrees()
this.yRot = yaw.toDegrees()
this.rotation.rotationYXZ(yaw, pitch, roll)
Camera.FORWARDS.rotate(this.rotation, this.forwards)
Camera.UP.rotate(this.rotation, this.up)
Camera.LEFT.rotate(this.rotation, this.left)
}
@@ -38,6 +38,7 @@ object RidingBehaviourSettingsAdapter : JsonDeserializer<RidingBehaviourSettings
JetAirBehaviour.KEY to JetAirSettings::class.java,
SwimDashBehaviour.KEY to SwimDashSettings::class.java,
VehicleLandBehaviour.KEY to VehicleLandSettings::class.java,
HoverBehaviour.KEY to HoverSettings::class.java,
CompositeBehaviour.KEY to CompositeSettings::class.java,
/*
@@ -0,0 +1,41 @@
{
"format_version": "1.8.0",
"animations": {
"animation.rotom_drone.sleep": {
"loop": true,
"bones": {
"body": {
"rotation": [
"math.sin(query.anim_time * 120) * 6",
0,
"math.cos(query.anim_time * 100) * 4"
],
"position": [
0,
"18 + math.sin(query.anim_time * 90) * 1",
0
]
},
"head": {
"relative_to": {
"rotation": "entity"
},
"rotation": [
0,
0,
0.01
]
}
}
},
"animation.rotom_drone.circle": {
"loop": true,
"bones": {
"rotom_drone": {
"rotation": [30, "90 - q.anim_time*90", 0],
"position": ["48*math.cos(q.anim_time*90)", 64, "48*math.sin(q.anim_time*90)"]
}
}
}
}
}
@@ -0,0 +1,208 @@
{
"format_version": "1.12.0",
"minecraft:geometry": [
{
"description": {
"identifier": "geometry.drone_rotom",
"texture_width": 64,
"texture_height": 32,
"visible_bounds_width": 8,
"visible_bounds_height": 6.5,
"visible_bounds_offset": [0, 2.75, 0]
},
"bones": [
{
"name": "rotom_drone",
"pivot": [0, 0, 0]
},
{
"name": "body",
"parent": "rotom_drone",
"pivot": [0, 8, 0]
},
{
"name": "head",
"parent": "body",
"pivot": [0, 6.5, 0],
"cubes": [
{"origin": [-5.5, 6.5, -3.5], "size": [11, 6, 7], "uv": [0, 0]}
]
},
{
"name": "eyes",
"parent": "head",
"pivot": [0.5, 6.5, -2.5]
},
{
"name": "eye_right",
"parent": "eyes",
"pivot": [-2.9, 9.5, -3.5],
"rotation": [0, 0, -7.5],
"cubes": [
{"origin": [-3.9, 7.5, -3.5], "size": [2, 4, 0], "inflate": 0.01, "uv": [0, 0], "mirror": true},
{"origin": [-3.9, 9, -3.5], "size": [2, 1, 0], "inflate": 0.02, "uv": [0, 6], "mirror": true}
]
},
{
"name": "pupil_right",
"parent": "eye_right",
"pivot": [-2.9, 9.5, -3.5],
"cubes": [
{"origin": [-3.4, 8, -3.5], "size": [1, 3, 0], "inflate": 0.03, "uv": [5, 0], "mirror": true}
]
},
{
"name": "eye_left",
"parent": "eyes",
"pivot": [2.9, 9.5, -3.5],
"rotation": [0, 0, 7.5],
"cubes": [
{"origin": [1.9, 7.5, -3.5], "size": [2, 4, 0], "inflate": 0.01, "uv": [0, 13]},
{"origin": [1.9, 9, -3.5], "size": [2, 1, 0], "inflate": 0.02, "uv": [0, 5]}
]
},
{
"name": "pupil_left",
"parent": "eye_left",
"pivot": [2.9, 9.5, -3.5],
"cubes": [
{"origin": [2.4, 8, -3.5], "size": [1, 3, 0], "inflate": 0.03, "uv": [6, 13]}
]
},
{
"name": "mouth_smile",
"parent": "head",
"pivot": [0, 7.55, -3.5],
"cubes": [
{"origin": [-1, 6.95, -3.5], "size": [2, 1, 0], "inflate": 0.02, "uv": [36, 7]},
{"origin": [-1.5, 7.25, -3.5], "size": [1, 1, 0], "inflate": 0.01, "uv": [40, 7]},
{"origin": [0.5, 7.25, -3.5], "size": [1, 1, 0], "inflate": 0.01, "uv": [42, 7]}
]
},
{
"name": "mouth_closed",
"parent": "head",
"pivot": [0, 7.45, -3.4],
"cubes": [
{"origin": [-0.5, 6.95, -3.4], "size": [1, 1, 0], "inflate": 0.02, "uv": [38, 8]}
]
},
{
"name": "mouth_open",
"parent": "head",
"pivot": [0, 7.45, -3.4],
"cubes": [
{"origin": [-0.5, 6.95, -3.4], "size": [1, 1, 0], "inflate": 0.02, "uv": [36, 8]}
]
},
{
"name": "mouth_sad",
"parent": "head",
"pivot": [0, 7.6, -3.3],
"cubes": [
{"origin": [-1, 7.3, -3.3], "size": [2, 1, 0], "inflate": 0.02, "uv": [36, 9]},
{"origin": [-1.5, 7, -3.3], "size": [1, 1, 0], "inflate": 0.01, "uv": [40, 9]},
{"origin": [0.5, 7, -3.3], "size": [1, 1, 0], "inflate": 0.01, "uv": [42, 9]}
]
},
{
"name": "head_spike1",
"parent": "head",
"pivot": [0, 12.5, 0],
"cubes": [
{"origin": [-1.5, 11.5, -1.5], "size": [3, 4, 3], "uv": [29, 0]}
]
},
{
"name": "head_spike2",
"parent": "head_spike1",
"pivot": [0, 15.5, 0],
"cubes": [
{"origin": [-1, 14.5, -1], "size": [2, 4, 2], "uv": [8, 13]}
]
},
{
"name": "head_spike3",
"parent": "head_spike2",
"pivot": [0, 18.5, 0],
"cubes": [
{"origin": [-0.5, 17.5, -0.5], "size": [1, 3, 1], "uv": [44, 6]}
]
},
{
"name": "torso",
"parent": "body",
"pivot": [0, 7, 0],
"cubes": [
{"origin": [-2, 3, -1.5], "size": [4, 4, 3], "uv": [34, 10]}
]
},
{
"name": "camera",
"parent": "torso",
"pivot": [0, 4.65, -1.25],
"cubes": [
{"origin": [-1, 3.65, -2.75], "size": [2, 2, 2], "uv": [24, 13]},
{"origin": [-0.5, 4.15, -2.75], "size": [1, 1, 0], "inflate": 0.01, "uv": [38, 0]}
]
},
{
"name": "propeller_front_right",
"parent": "torso",
"pivot": [-1.5, 5, -1],
"rotation": [0, 45, 0],
"cubes": [
{"origin": [-2, 5, -3.5], "size": [1, 0, 3], "uv": [37, 0]},
{"origin": [-5.5, 5, -11.5], "size": [8, 0, 8], "uv": [40, 0]}
]
},
{
"name": "propeller_front_left",
"parent": "torso",
"pivot": [1.5, 5, -1],
"rotation": [0, -45, 0],
"cubes": [
{"origin": [1, 5, -3.5], "size": [1, 0, 3], "uv": [27, 0]},
{"origin": [-2.5, 5, -11.5], "size": [8, 0, 8], "uv": [40, 0]}
]
},
{
"name": "propeller_back_right",
"parent": "torso",
"pivot": [-1.5, 5, 1],
"rotation": [0, -45, 0],
"cubes": [
{"origin": [-2, 5, 0.5], "size": [1, 0, 3], "uv": [39, 0]},
{"origin": [-5.5, 5, 3.5], "size": [8, 0, 8], "uv": [40, 0]}
]
},
{
"name": "propeller_back_left",
"parent": "torso",
"pivot": [1.5, 5, 1],
"rotation": [0, 45, 0],
"cubes": [
{"origin": [1, 5, 0.5], "size": [1, 0, 3], "uv": [42, 3]},
{"origin": [-2.5, 5, 3.5], "size": [8, 0, 8], "uv": [40, 0]}
]
},
{
"name": "tail1",
"parent": "torso",
"pivot": [0, 3, 0],
"cubes": [
{"origin": [-1, 1, -1], "size": [2, 3, 2], "uv": [16, 13]}
]
},
{
"name": "tail2",
"parent": "tail1",
"pivot": [0, 1, 0],
"cubes": [
{"origin": [-0.5, -1, -0.5], "size": [1, 3, 1], "uv": [41, 3]}
]
}
]
}
]
}
@@ -0,0 +1,8 @@
{
"poses": {
"sleep": {
"poseTypes": ["SLEEP"],
"animations": ["q.bedrock('rotom_drone', 'sleep')"]
}
}
}
@@ -0,0 +1,13 @@
{
"name": "cobblemon:rotom_drone",
"order": 0,
"variations": [
{
"aspects": [],
"poser": "cobblemon:rotom_drone",
"model": "cobblemon:rotom_drone.geo",
"texture": "cobblemon:textures/drone/rotom_drone.png",
"layers": []
}
]
}
@@ -0,0 +1,28 @@
{
"format_version": "1.8.0",
"animations": {
"animation.ride_test.sitting": {
"loop": true,
"bones": {
"body": {
"position": [0, -9, 0]
},
"torso": {
"rotation": [25, 0, 0]
},
"arm_right": {
"rotation": [0, 0, 22.5]
},
"arm_left": {
"rotation": [0, 0, -27.5]
},
"leg_right": {
"rotation": [-90, 20, 0]
},
"leg_left": {
"rotation": [-90, -20, 0]
}
}
}
}
}
@@ -2272,23 +2272,59 @@
"eyelid_right": {
"position": {
"0.0": [0, 0, 0],
"0.4167": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
"0.5833": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
"2.0417": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
"2.375": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
"3.0": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
"5.875": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]}
"0.4167": {
"pre": [0, 0, 0],
"post": [-0.1, 0.1, 0]
},
"0.5833": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
},
"2.0417": {
"pre": [0, 0, 0],
"post": [-0.1, 0.1, 0]
},
"2.375": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
},
"3.0": {
"pre": [0, 0, 0],
"post": [-0.1, 0.1, 0]
},
"5.875": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, 0],
"0.4167": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
"0.5833": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
"2.0417": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
"2.375": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
"3.0": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
"5.875": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]}
"0.4167": {
"pre": [0, 0, 0],
"post": [0.1, 0.1, 0]
},
"0.5833": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
},
"2.0417": {
"pre": [0, 0, 0],
"post": [0.1, 0.1, 0]
},
"2.375": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
},
"3.0": {
"pre": [0, 0, 0],
"post": [0.1, 0.1, 0]
},
"5.875": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
}
}
}
}
@@ -2553,15 +2589,27 @@
"eyelid_right": {
"position": {
"0.0": [0, 0, 0],
"1.25": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
"3.6667": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]}
"1.25": {
"pre": [0, 0, 0],
"post": [-0.1, 0.1, 0]
},
"3.6667": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, 0],
"1.25": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
"3.6667": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]}
"1.25": {
"pre": [0, 0, 0],
"post": [0.1, 0.1, 0]
},
"3.6667": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
}
}
},
"jaw": {
@@ -8763,19 +8811,43 @@
"eyelid_right": {
"position": {
"0.0": [0, 0, 0],
"0.25": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
"0.5": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
"2.25": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
"2.4583": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]}
"0.25": {
"pre": [0, 0, 0],
"post": [-0.1, 0.1, 0]
},
"0.5": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
},
"2.25": {
"pre": [0, 0, 0],
"post": [-0.1, 0.1, 0]
},
"2.4583": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, 0],
"0.25": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
"0.5": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
"2.25": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
"2.4583": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]}
"0.25": {
"pre": [0, 0, 0],
"post": [0.1, 0.1, 0]
},
"0.5": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
},
"2.25": {
"pre": [0, 0, 0],
"post": [0.1, 0.1, 0]
},
"2.4583": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
}
}
}
}
@@ -11221,23 +11293,59 @@
"eyelid_right": {
"position": {
"0.0": [0, 0, 0],
"0.25": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
"0.4167": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
"0.8333": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
"1.125": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
"2.5417": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
"2.6667": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]}
"0.25": {
"pre": [0, 0, 0],
"post": [-0.1, 0.1, 0]
},
"0.4167": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
},
"0.8333": {
"pre": [0, 0, 0],
"post": [-0.1, 0.1, 0]
},
"1.125": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
},
"2.5417": {
"pre": [0, 0, 0],
"post": [-0.1, 0.1, 0]
},
"2.6667": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, 0],
"0.25": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
"0.4167": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
"0.8333": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
"1.125": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
"2.5417": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
"2.6667": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]}
"0.25": {
"pre": [0, 0, 0],
"post": [0.1, 0.1, 0]
},
"0.4167": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
},
"0.8333": {
"pre": [0, 0, 0],
"post": [0.1, 0.1, 0]
},
"1.125": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
},
"2.5417": {
"pre": [0, 0, 0],
"post": [0.1, 0.1, 0]
},
"2.6667": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
}
}
},
"locator_target": {
@@ -13529,19 +13637,43 @@
"eyelid_right": {
"position": {
"0.0": [0, 0, 0],
"0.3333": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
"1.2083": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
"2.5417": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
"2.7083": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]}
"0.3333": {
"pre": [0, 0, 0],
"post": [-0.1, 0.1, 0]
},
"1.2083": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
},
"2.5417": {
"pre": [0, 0, 0],
"post": [-0.1, 0.1, 0]
},
"2.7083": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, 0],
"0.3333": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
"1.2083": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
"2.5417": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
"2.7083": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]}
"0.3333": {
"pre": [0, 0, 0],
"post": [0.1, 0.1, 0]
},
"1.2083": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
},
"2.5417": {
"pre": [0, 0, 0],
"post": [0.1, 0.1, 0]
},
"2.7083": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
}
}
},
"locator_mouth": {
@@ -13740,14 +13872,20 @@
"position": {
"0.0": [-0.1, 0.1, 0],
"0.125": [-0.1, 0.1, 0],
"0.1667": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]}
"0.1667": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
}
}
},
"eyelid_left": {
"position": {
"0.0": [0.1, 0.1, 0],
"0.125": [0.1, 0.1, 0],
"0.1667": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]}
"0.1667": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
}
}
},
"jaw": {
@@ -14543,7 +14681,7 @@
"rotation": [0, -6, -15]
},
"wing_right_elbow": {
"rotation": [0, "-6", -15],
"rotation": [0, "-6+", -15],
"position": [0.45, 0.1, 0]
},
"wing_right_membrane": {
@@ -16036,7 +16174,7 @@
"animation_length": 4,
"bones": {
"body": {
"rotation": [22.5, 0, "math.sin(q.anim_time*90*1-90)*-0.5"],
"rotation": ["22.5 + q.riding.pitch(0)*-90", 0, "math.sin(q.anim_time*90*1-90)*-0.5"],
"position": ["math.cos(q.anim_time*90*1-60)*1", "12+math.cos((q.anim_time*90*2-60)+math.sin(q.anim_time*90*2)*20)*3", 0]
},
"torso": {
@@ -17357,6 +17495,14 @@
"locator_top": {
"position": [0, 13, 0]
}
},
"sound_effects": {
"1.125": {
"effect": "animation.leather.wing_flap.medium"
},
"3.1667": {
"effect": "animation.leather.wing_flap.medium"
}
}
},
"animation.charizard.air_fly": {
@@ -18633,6 +18779,17 @@
},
"locator_top": {
"position": [0, -1, 0]
},
"locator_seat_1": {
"rotation": [-60, 0, 0]
}
},
"sound_effects": {
"1.0833": {
"effect": "animation.leather.wing_flap.medium"
},
"3.0833": {
"effect": "animation.leather.wing_flap.medium"
}
}
},
@@ -18898,6 +19055,9 @@
},
"locator_top": {
"position": [0, -6, 0]
},
"locator_seat_1": {
"rotation": [-60, 0, 0]
}
}
},
@@ -19097,23 +19257,59 @@
"eyelid_right": {
"position": {
"0.0": [0, 0, 0],
"0.4167": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
"0.5833": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
"2.4167": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
"2.5833": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
"3.9167": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
"4.0833": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]}
"0.4167": {
"pre": [0, 0, 0],
"post": [-0.1, 0.1, 0]
},
"0.5833": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
},
"2.4167": {
"pre": [0, 0, 0],
"post": [-0.1, 0.1, 0]
},
"2.5833": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
},
"3.9167": {
"pre": [0, 0, 0],
"post": [-0.1, 0.1, 0]
},
"4.0833": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, 0],
"0.4167": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
"0.5833": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
"2.4167": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
"2.5833": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
"3.9167": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
"4.0833": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]}
"0.4167": {
"pre": [0, 0, 0],
"post": [0.1, 0.1, 0]
},
"0.5833": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
},
"2.4167": {
"pre": [0, 0, 0],
"post": [0.1, 0.1, 0]
},
"2.5833": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
},
"3.9167": {
"pre": [0, 0, 0],
"post": [0.1, 0.1, 0]
},
"4.0833": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
}
}
}
}
@@ -22458,7 +22654,10 @@
},
"0.5": [0.78, -10.13, 0.45],
"0.5417": [-0.45, -8.03, 0.45],
"0.5833": {"pre": [-0.45, -8.03, 0.45], "post": [-0.45, "-7.79+360", 0.45]},
"0.5833": {
"pre": [-0.45, -8.03, 0.45],
"post": [-0.45, "-7.79+360", 0.45]
},
"0.625": [-2.7, 355.37, 0.45],
"1.0": {
"pre": [-9.46, "10.71+360", 0.5],
@@ -26129,23 +26328,59 @@
"eyelid_right": {
"position": {
"0.0": [0, 0, 0],
"0.0833": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
"0.3333": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
"1.625": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
"1.8333": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
"2.5": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
"2.625": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]}
"0.0833": {
"pre": [0, 0, 0],
"post": [-0.1, 0.1, 0]
},
"0.3333": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
},
"1.625": {
"pre": [0, 0, 0],
"post": [-0.1, 0.1, 0]
},
"1.8333": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
},
"2.5": {
"pre": [0, 0, 0],
"post": [-0.1, 0.1, 0]
},
"2.625": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, 0],
"0.0833": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
"0.3333": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
"1.625": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
"1.8333": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
"2.5": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
"2.625": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]}
"0.0833": {
"pre": [0, 0, 0],
"post": [0.1, 0.1, 0]
},
"0.3333": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
},
"1.625": {
"pre": [0, 0, 0],
"post": [0.1, 0.1, 0]
},
"1.8333": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
},
"2.5": {
"pre": [0, 0, 0],
"post": [0.1, 0.1, 0]
},
"2.625": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
}
}
},
"locator_root": {
@@ -29385,9 +29620,15 @@
"brow": {
"position": {
"0.9583": [0, 0, 0],
"1.1667": {"pre": [0, 0, 0], "post": [0, 0, -0.3]},
"1.1667": {
"pre": [0, 0, 0],
"post": [0, 0, -0.3]
},
"2.2917": [0, 0, -0.3],
"2.5417": {"pre": [0, 0, -0.3], "post": [0, 0, 0]}
"2.5417": {
"pre": [0, 0, -0.3],
"post": [0, 0, 0]
}
}
},
"jaw": {
@@ -29722,19 +29963,43 @@
"eyelid_right": {
"position": {
"0.0": [0, 0, 0],
"0.3333": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
"1.2083": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
"2.375": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
"2.6667": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]}
"0.3333": {
"pre": [0, 0, 0],
"post": [-0.1, 0.1, 0]
},
"1.2083": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
},
"2.375": {
"pre": [0, 0, 0],
"post": [-0.1, 0.1, 0]
},
"2.6667": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, 0],
"0.3333": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
"1.2083": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
"2.375": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
"2.6667": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]}
"0.3333": {
"pre": [0, 0, 0],
"post": [0.1, 0.1, 0]
},
"1.2083": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
},
"2.375": {
"pre": [0, 0, 0],
"post": [0.1, 0.1, 0]
},
"2.6667": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
}
}
},
"locator_root": {
@@ -29753,6 +30018,106 @@
}
}
},
"animation.charizard.ride_air_look": {
"loop": true,
"bones": {
"body": {
"rotation": ["q.riding.pitch_change(0)*-0", "q.riding.yaw_change(0)*-15", "q.riding.roll_change(0)*15"]
},
"neck": {
"rotation": ["math.clamp(q.riding.pitch_change(0),-0.5,1.0)*-20", 0, "q.riding.yaw_change(0)*7"]
},
"neck2": {
"rotation": ["math.clamp(q.riding.pitch_change(0),-0.5,1.0)*-12", 0, "q.riding.yaw_change(0)*12"]
},
"neck3": {
"rotation": ["q.riding.pitch_change(0)*-7", 0, "q.riding.yaw_change(0)*7"]
},
"neck4": {
"rotation": ["q.riding.pitch_change(0)*-7", 0, "q.riding.yaw_change(0)*7"]
},
"head_angle": {
"rotation": ["q.riding.pitch_change(0)*-7", 0, "q.riding.yaw_change(0)*7"]
},
"shoulder_right": {
"rotation": [0, "-12.5*q.riding.pitch_change(0)", "27.5*q.riding.yaw_change(0)"]
},
"arm_right": {
"rotation": [0, "15*q.riding.yaw_change(0)", 0]
},
"forearm_right": {
"rotation": [0, "15*q.riding.yaw_change(0)", "-12.5*q.riding.pitch_change(0)"]
},
"shoulder_left": {
"rotation": [0, "12.5*q.riding.pitch_change(0)", "27.5*q.riding.yaw_change(0)"]
},
"arm_left": {
"rotation": [0, "15*q.riding.yaw_change(0)", 0]
},
"forearm_left": {
"rotation": [0, "15*q.riding.yaw_change(0)", "12.5*q.riding.pitch_change(0)"]
},
"wing_right_base": {
"rotation": ["-5*q.riding.pitch_change(0)", 0, 0]
},
"wing_right_bend": {
"rotation": ["10*q.riding.yaw_change(0)", "7.5*q.riding.pitch_change(0)", "10*q.riding.yaw_change(0)"]
},
"wing_right_mid": {
"rotation": ["-5*q.riding.pitch_change(0)", 0, 0]
},
"wing_right_elbow": {
"rotation": ["-2.5*q.riding.pitch_change(0)", "5*q.riding.pitch_change(0)", 0]
},
"wing_left_base": {
"rotation": ["-5*q.riding.pitch_change(0)", 0, 0]
},
"wing_left_bend": {
"rotation": ["-10*q.riding.yaw_change(0)", "-7.5*q.riding.pitch_change(0)", "-10*q.riding.yaw_change(0)"]
},
"wing_left_mid": {
"rotation": ["-5*q.riding.pitch_change(0)", 0, 0]
},
"wing_left_elbow": {
"rotation": ["-2.5*q.riding.pitch_change(0)", "-(5*q.riding.pitch_change(0))", 0]
},
"tail": {
"rotation": ["q.riding.pitch_change(0)*7", 0, "q.riding.yaw_change(0)*-10"]
},
"tail2": {
"rotation": ["q.riding.pitch_change(0)*7", "q.riding.yaw_change(0)*15", 0]
},
"tail3": {
"rotation": ["q.riding.pitch_change(0)*7", "q.riding.yaw_change(0)*20", 0]
},
"tail4": {
"rotation": ["q.riding.pitch_change(0)*7", "q.riding.yaw_change(0)*20", 0]
},
"tail5": {
"rotation": ["q.riding.pitch_change(0)*8", "q.riding.yaw_change(0)*20", 0]
},
"leg_right": {
"rotation": ["-12.5*q.riding.pitch_change(0)", "q.riding.yaw_change(0)*20", 0],
"position": ["-1.5*q.riding.yaw_change(0)", 0, 0]
},
"knee_right": {
"rotation": ["-12.5*q.riding.pitch_change(0)", 0, 0]
},
"foot_right": {
"rotation": ["-12.5*q.riding.pitch_change(0)", 0, 0]
},
"leg_left": {
"rotation": ["-12.5*q.riding.pitch_change(0)", "q.riding.yaw_change(0)*20", 0],
"position": ["-1.5*q.riding.yaw_change(0)", 0, 0]
},
"knee_left": {
"rotation": ["-12.5*q.riding.pitch_change(0)", 0, 0]
},
"foot_left": {
"rotation": ["-12.5*q.riding.pitch_change(0)", 0, 0]
}
}
},
"animation.charizard.air_status": {
"animation_length": 3,
"bones": {
@@ -32994,19 +33359,43 @@
"eyelid_right": {
"position": {
"0.0": [0, 0, 0],
"0.3333": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
"1.2083": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
"2.2083": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
"2.4583": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]}
"0.3333": {
"pre": [0, 0, 0],
"post": [-0.1, 0.1, 0]
},
"1.2083": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
},
"2.2083": {
"pre": [0, 0, 0],
"post": [-0.1, 0.1, 0]
},
"2.4583": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, 0],
"0.3333": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
"1.2083": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
"2.2083": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
"2.4583": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]}
"0.3333": {
"pre": [0, 0, 0],
"post": [0.1, 0.1, 0]
},
"1.2083": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
},
"2.2083": {
"pre": [0, 0, 0],
"post": [0.1, 0.1, 0]
},
"2.4583": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
}
}
},
"locator_root": {
@@ -34432,14 +34821,20 @@
"position": {
"0.0": [-0.1, 0.1, 0],
"0.125": [-0.1, 0.1, 0],
"0.1667": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]}
"0.1667": {
"pre": [-0.1, 0.1, 0],
"post": [0, 0, 0]
}
}
},
"eyelid_left": {
"position": {
"0.0": [0.1, 0.1, 0],
"0.125": [0.1, 0.1, 0],
"0.1667": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]}
"0.1667": {
"pre": [0.1, 0.1, 0],
"post": [0, 0, 0]
}
}
}
}
@@ -535,6 +535,11 @@
}
}
}
},
"sound_effects": {
"0.5": {
"effect": "animation.plumage.wing_flap.medium"
}
}
},
"animation.pidgeot.air_fly": {
@@ -710,6 +715,9 @@
},
"wing_open_right4": {
"rotation": [0, 0, "7.5+math.sin(q.anim_time*90*0.8-240)*-10+math.sin(q.anim_time*90*12-120)*0.4"]
},
"locator_seat1": {
"position": [0, 1.5, -4]
}
}
},
@@ -1566,6 +1574,11 @@
}
}
}
},
"sound_effects": {
"1.375": {
"effect": "animation.plumage.wing_flap.medium"
}
}
},
"animation.pidgeot.air_fly_quirk2": {
@@ -2721,6 +2734,14 @@
}
}
}
},
"sound_effects": {
"1.4583": {
"effect": "animation.plumage.wing_flap.medium"
},
"3.0833": {
"effect": "animation.plumage.wing_flap.medium"
}
}
},
"animation.pidgeot.blink": {
@@ -467,6 +467,7 @@
},
"animation.aerodactyl.air_idle": {
"loop": true,
"animation_length": 1.33333,
"bones": {
"aerodactyl": {
"position": [0, 3, 0]
@@ -642,10 +643,16 @@
"right_wing_membrane": {
"rotation": [0, "0+math.sin(q.anim_time*90*3+90)*3", "0+math.sin(q.anim_time*90*3+90)*1.5"]
}
},
"sound_effects": {
"1.0833": {
"effect": "animation.leather.wing_flap.medium"
}
}
},
"animation.aerodactyl.air_fly": {
"loop": true,
"animation_length": 1.33333,
"bones": {
"aerodactyl": {
"position": [0, 3, 0]
@@ -827,6 +834,11 @@
"right_horn": {
"rotation": ["math.sin(q.anim_time*90*12-160)*2", 0, 0]
}
},
"sound_effects": {
"0.9583": {
"effect": "animation.leather.wing_flap.medium"
}
}
},
"animation.aerodactyl.sleep": {
@@ -1237,6 +1237,20 @@
"rotation": ["-math.sin(q.anim_time*90*2-120)*4", 0, 0],
"position": [0, "7.8+math.sin(q.anim_time*90*2)*2", -5.6]
}
},
"sound_effects": {
"1.5": {
"effect": "animation.leather.wing_flap.medium"
},
"3.5": {
"effect": "animation.leather.wing_flap.medium"
},
"5.5": {
"effect": "animation.leather.wing_flap.medium"
},
"7.5": {
"effect": "animation.leather.wing_flap.medium"
}
}
},
"animation.dragonite.water_idle": {
@@ -2053,6 +2067,89 @@
"effect": "pokemon.dragonite.cry"
}
}
},
"animation.dragonite.shock": {
"loop": true,
"bones": {
"pupil_left": {
"scale": [0.7, 0.7, 1]
},
"eye_shine_left": {
"position": [0, -0.5, 0]
},
"pupil_right": {
"scale": [0.7, 0.7, 1]
},
"eye_shine_right": {
"position": [0, -0.5, 0]
},
"jaw": {
"rotation": [27.5, 0, 0]
},
"eye_left": {
"position": [0, 0, 0],
"scale": 1
},
"eye_shocked_left": {
"position": [0.25, 0, -0.26]
},
"eye_shocked_right": {
"position": [-0.125, 0, -0.18]
}
}
},
"animation.dragonite.angry": {
"loop": true,
"bones": {
"eye_angry_left": {
"position": [0.1, 0, -0.1]
},
"eye_shine_left": {
"position": [0, -1, 0]
},
"eye_shine_right": {
"position": [0, -1, 0]
},
"eye_angry_right": {
"position": [-0.1, 0, -0.1]
}
}
},
"animation.dragonite.sad": {
"loop": true,
"bones": {
"eye_sad_left": {
"position": [0.1, 0, -0.1]
},
"eye_sad_right": {
"position": [-0.1, 0, -0.1]
}
}
},
"animation.dragonite.happy": {
"loop": true,
"bones": {
"eyelid_happy_left": {
"position": [0.1, 0, -0.1]
},
"eyelid_happy_right": {
"position": [-0.1, 0, -0.1]
},
"jaw": {
"rotation": [27.5, 0, 0]
}
}
},
"animation.dragonite.hurt": {
"loop": true,
"bones": {
"eyelid_recoil_left": {
"position": [0.1, 0, -0.1]
},
"eyelid_recoil_right": {
"position": [-0.1, 0, -0.1]
}
}
}
}
}
@@ -5,7 +5,11 @@
"loop": true,
"bones": {
"body": {
"rotation": [0, "0 - Math.Sin(((q.anim_time + 0.1) * 180 * 0.5) * 1) * 5", "Math.Sin(((q.anim_time + 0.4) * 180 * 0.5) * 1) * 5"],
"rotation": [
"45*q.riding.velocity_forward(0)",
"0 - Math.Sin(((q.anim_time + 0.1) * 180 * 0.5) * 1) * 5",
"Math.Sin(((q.anim_time + 0.4) * 180 * 0.5) * 1) * 5 + 45*q.riding.velocity_right(0)"
],
"position": ["Math.Sin((q.anim_time * 180 * 0.5) * 1) * 1.5", "7+Math.Sin((q.anim_time * 90 * 0.5) * 1) * 1.5", 0]
},
"magnet_back_rotation": {
@@ -45,7 +49,11 @@
"loop": true,
"bones": {
"body": {
"rotation": [15, "0 - Math.Sin(((q.anim_time + 0.1) * 180 * 0.5) * 1) * 5", "Math.Sin(((q.anim_time + 0.4) * 180 * 0.5) * 1) * 5"],
"rotation": [
"2.5 + 45*q.riding.velocity_forward(0)",
"- Math.Sin(((q.anim_time + 0.1) * 180 * 0.5) * 1) * 5",
"Math.Sin(((q.anim_time + 0.4) * 180 * 0.5) * 1) * 5 - 45*q.riding.velocity_right(0)"
],
"position": ["Math.Sin((q.anim_time * 180 * 0.5) * 1) * 1.5", "7+Math.Sin((q.anim_time * 90 * 0.5) * 1) * 1.5", 0]
},
"magnet_back_rotation": {
@@ -266,45 +274,117 @@
"pupil_left": {
"position": {
"0.0": [0, 0, 0],
"0.5": {"pre": [0, 0, 0], "post": [0, 0, 0]},
"0.5417": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
"1.75": {"pre": [0, 0, 0.1], "post": [0, 0, 0.1]},
"1.7917": {"pre": [0, 0, 0.1], "post": [0, 0, 0]},
"2.0833": {"pre": [0, 0, 0], "post": [0, 0, 0]},
"2.125": {"pre": [0, 0, 0], "post": [0, 0, 0.1]}
"0.5": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
},
"0.5417": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
},
"1.75": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0.1]
},
"1.7917": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0]
},
"2.0833": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
},
"2.125": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
}
}
},
"pupil_closed_left": {
"position": {
"0.0": [0, 0, 0],
"0.5": {"pre": [0, 0, 0], "post": [0, 0, 0]},
"0.5417": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
"1.75": {"pre": [0, 0, -0.1], "post": [0, 0, -0.1]},
"1.7917": {"pre": [0, 0, -0.1], "post": [0, 0, 0]},
"2.0833": {"pre": [0, 0, 0], "post": [0, 0, 0]},
"2.125": {"pre": [0, 0, 0], "post": [0, 0, -0.1]}
"0.5": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
},
"0.5417": {
"pre": [0, 0, 0],
"post": [0, 0, -0.1]
},
"1.75": {
"pre": [0, 0, -0.1],
"post": [0, 0, -0.1]
},
"1.7917": {
"pre": [0, 0, -0.1],
"post": [0, 0, 0]
},
"2.0833": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
},
"2.125": {
"pre": [0, 0, 0],
"post": [0, 0, -0.1]
}
}
},
"pupil_right": {
"position": {
"0.0": [0, 0, 0],
"0.2083": {"pre": [0, 0, 0], "post": [0, 0, 0]},
"0.25": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
"0.5": {"pre": [0, 0, 0.1], "post": [0, 0, 0.1]},
"0.5417": {"pre": [0, 0, 0.1], "post": [0, 0, 0]},
"1.9583": {"pre": [0, 0, 0], "post": [0, 0, 0]},
"2.0": {"pre": [0, 0, 0], "post": [0, 0, 0.1]}
"0.2083": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
},
"0.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
},
"0.5": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0.1]
},
"0.5417": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0]
},
"1.9583": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
},
"2.0": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
}
}
},
"pupil_closed_right": {
"position": {
"0.0": [0, 0, 0],
"0.2083": {"pre": [0, 0, 0], "post": [0, 0, 0]},
"0.25": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
"0.5": {"pre": [0, 0, -0.1], "post": [0, 0, -0.1]},
"0.5417": {"pre": [0, 0, -0.1], "post": [0, 0, 0]},
"1.9583": {"pre": [0, 0, 0], "post": [0, 0, 0]},
"2.0": {"pre": [0, 0, 0], "post": [0, 0, -0.1]}
"0.2083": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
},
"0.25": {
"pre": [0, 0, 0],
"post": [0, 0, -0.1]
},
"0.5": {
"pre": [0, 0, -0.1],
"post": [0, 0, -0.1]
},
"0.5417": {
"pre": [0, 0, -0.1],
"post": [0, 0, 0]
},
"1.9583": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
},
"2.0": {
"pre": [0, 0, 0],
"post": [0, 0, -0.1]
}
}
}
},
@@ -155,6 +155,9 @@
"back_neck_braid_right4": {
"rotation": [2.5, 0, -10],
"position": [-0.5, 0, 0]
},
"body": {
"rotation": ["q.riding.velocity_y(0)*-90", 0, 0]
}
}
},
@@ -650,7 +653,7 @@
}
},
"neck2": {
"rotation": ["5+math.sin(q.anim_time*90*4-60)*2", 0, 0]
"rotation": ["5+math.sin(q.anim_time*90*4-60)*2 - math.pow(q.riding.yaw_change(0),2)*20", "q.riding.yaw_change(0)*-10", "q.riding.yaw_change(0)*10"]
},
"tail5": {
"rotation": ["-7.5+math.sin(q.anim_time*90*4-90)*2", "math.sin(q.anim_time*90*2)*1", "math.sin(q.anim_time*90*2)*4"]
@@ -677,7 +680,7 @@
}
},
"neck": {
"rotation": ["3+math.sin(q.anim_time*90*4-30)*1", 0, "math.sin(q.anim_time*90*2-30)*2"]
"rotation": ["3+math.sin(q.anim_time*90*4-30)*1", "q.riding.yaw_change(0)*-10", "math.sin(q.anim_time*90*2-30)*2 + q.riding.yaw_change(0)*10"]
},
"front_neck_braid_left": {
"rotation": ["5+math.sin(q.anim_time*90*4-60)*1", 0.5, 5]
@@ -844,6 +847,7 @@
"position": [-0.5, 0, 0]
},
"body": {
"rotation": ["q.riding.velocity_y(0)*-90", 0, 0],
"position": {
"0.0": [0, 0, 0],
"0.0417": [0, -0.25, 0],
@@ -1257,7 +1261,7 @@
}
},
"neck2": {
"rotation": ["math.sin(q.anim_time*90*4-60)*4", 0, 0]
"rotation": ["math.sin(q.anim_time*90*4-60)*4 - math.pow(q.riding.yaw_delta(0),2)*20", "q.riding.yaw_delta(0)*-10", "q.riding.yaw_delta(0)*10"]
},
"tail5": {
"rotation": ["-10+math.sin(q.anim_time*90*4-100)*6", "math.sin(q.anim_time*90*4-40)*2", "math.sin(q.anim_time*90*4-20)*1"]
@@ -1279,7 +1283,7 @@
}
},
"neck": {
"rotation": ["13+math.sin(q.anim_time*90*4-30)*7", 0, 0],
"rotation": ["13+math.sin(q.anim_time*90*4-30)*7", "q.riding.yaw_delta(0)*-10", "q.riding.yaw_delta(0)*10"],
"position": [0, 0, "-0.5+math.sin(q.anim_time*90*4-30)*0.2"]
},
"front_neck_braid_left": {
@@ -458,8 +458,21 @@
"2.125": [0, -42.5, 0],
"2.3333": [0, -47.5, 0]
}
},
"locator_camera": {
"relative_to": {
"rotation": "entity"
},
"position": {
"0.0": [-24, 12, -23],
"0.91667": [20, 11, -15]
},
"rotation": {
"0.0": [0, -145, 0],
"0.91667": [0, -215, 0]
}
}
}
}
}
}
}
@@ -1343,6 +1343,27 @@
"2.2083": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
"2.3333": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
}
},
"locator_camera": {
"relative_to": {
"rotation": "entity"
},
"position": {
"0.0": [0, 45, -42],
"0.125": [0, 16, -42],
"1.20833": [0, 16, -42],
"1.41667": [0, 66, -26],
"2.20833": [0, 72, -11],
"2.33333": [0, 26, -37]
},
"rotation": {
"0.0": [197.5, 2.5, -180],
"0.125": [172.5, 2.5, -180],
"1.20833": [172.5, 2.5, -180],
"1.41667": [227.5, 2.5, -180],
"2.20833": [245, 2.5, -180],
"2.33333": [185, 2.5, -180]
}
}
},
"sound_effects": {
@@ -3632,6 +3653,27 @@
"0.2083": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
"1.375": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
}
},
"locator_camera": {
"relative_to": {
"rotation": "entity"
},
"position": {
"0.0": [0, 22, -44],
"0.25": [-41, 22, -25],
"1.20833": [-41, 22, -25],
"1.45833": [40, 22, -28],
"2": [40, 22, -28],
"2.20833": [0, 22, -61]
},
"rotation": {
"0.0": [0, 180, 0],
"0.25": [0, 227.5, 0],
"1.20833": [0, 227.5, 0],
"1.45833": [0, 127.5, 0],
"2": [0, 127.5, 0],
"2.20833": [0, 180, 0]
}
}
},
"sound_effects": {
@@ -5910,4 +5952,4 @@
}
}
}
}
}
@@ -7,8 +7,8 @@
"texture_width": 256,
"texture_height": 128,
"visible_bounds_width": 10,
"visible_bounds_height": 5,
"visible_bounds_offset": [0, 1.5, 0]
"visible_bounds_height": 6,
"visible_bounds_offset": [0, 2, 0]
},
"bones": [
{
@@ -20,7 +20,7 @@
"parent": "charizard",
"pivot": [0, 0, -1],
"locators": {
"root": [0, 0, 0]
"root": [0, 0, -1]
}
},
{
@@ -28,7 +28,7 @@
"parent": "charizard",
"pivot": [0, 41, -1],
"locators": {
"top": [0, 41, 0]
"top": [0, 41, -1]
}
},
{
@@ -116,7 +116,8 @@
{
"name": "head_correction",
"parent": "head",
"pivot": [0, 43.5, -0.5]
"pivot": [0, 43.5, -0.5],
"rotation": [-95, 0, 0]
},
{
"name": "head_ai",
@@ -127,20 +128,15 @@
"name": "head_angle",
"parent": "head_ai",
"pivot": [0, 43.5, -0.5],
"rotation": [95, 0, 0],
"cubes": [
{"origin": [-3.5, 41.5, -2], "size": [7, 7, 5], "uv": [48, 0]},
{"origin": [-3.5, 41.5, -4], "size": [7, 4, 2], "uv": [95, 64]}
{"origin": [-3.5, 41.5, -4], "size": [7, 4, 2], "uv": [95, 64]},
{"origin": [-2.5, 48, -2], "size": [5, 5, 2], "inflate": 0.02, "uv": [37, 31]},
{"origin": [-2, 51.48744, -3.03033], "size": [0, 1, 1], "inflate": 0.01, "pivot": [-2, 52.51777, -2], "rotation": [45, 0, 15], "uv": [43, 42]},
{"origin": [2, 51.48744, -3.03033], "size": [0, 1, 1], "inflate": 0.01, "pivot": [2, 52.51777, -2], "rotation": [45, 0, -15], "uv": [41, 42]}
]
},
{
"name": "item_hat",
"parent": "head_angle",
"pivot": [0, 45, 3],
"rotation": [-90, 0, 0],
"locators": {
"item_hat": [0, 45, 3]
}
},
{
"name": "locator_head",
"parent": "head_angle",
@@ -150,51 +146,59 @@
"head": [0, 46.5, 3]
}
},
{
"name": "locator_face",
"parent": "head_angle",
"pivot": [0, 53.75, -0.25],
"rotation": [-90, 0, 0],
"locators": {
"face": [0, 53.75, -0.25]
}
},
{
"name": "locator_item_face",
"parent": "head_angle",
"pivot": [0, 48.5, 0.5],
"rotation": [-90, 0, 0],
"locators": {
"item_face": [0, 48.5, 0.5]
}
},
{
"name": "locator_mouth",
"parent": "head_angle",
"pivot": [0, 45.75, -2],
"pivot": [0, 48.75, -3],
"rotation": [-90, 0, 0],
"locators": {
"mouth": [0, 45.75, -2],
"special": [0, 45.75, -2]
"mouth": [0, 48.75, -3]
}
},
{
"name": "eyes",
"name": "locator_special_attack",
"parent": "head_angle",
"pivot": [0, -3.5, 1.5]
"pivot": [0, 48.75, -3],
"rotation": [-90, 0, 0],
"locators": {
"special_attack": [0, 48.75, -3]
}
},
{
"name": "locator_jaw_upper",
"parent": "head_angle",
"pivot": [0, 51.75, -2.25],
"rotation": [-90, 0, 0],
"locators": {
"jaw1": [0, 51.75, -2.25]
}
},
{
"name": "brow",
"parent": "eyes",
"parent": "head_angle",
"pivot": [0, 48.275, 1.765],
"cubes": [
{"origin": [-2.5, 48.55, 1], "size": [5, 0, 1], "uv": [0, 14]},
{"origin": [-3.5, 47.5, 1.53], "size": [7, 1, 1], "inflate": 0.04, "uv": [0, 12]}
]
},
{
"name": "eye",
"parent": "head_angle",
"pivot": [0, -3.5, 1.5]
},
{
"name": "locator_face",
"parent": "eye",
"pivot": [0, 53.75, -0.25],
"rotation": [-90, 0, 0],
"locators": {
"face": [0, 53.75, -0.25]
}
},
{
"name": "eye_right",
"parent": "eyes",
"parent": "eye",
"pivot": [-2.75, 47.75, 0.875],
"cubes": [
{"origin": [-3.5, 47.5, 0], "size": [2, 1, 2], "inflate": 0.01, "uv": [106, 36]},
@@ -222,7 +226,7 @@
},
{
"name": "eye_left",
"parent": "eyes",
"parent": "eye",
"pivot": [2.75, 47.75, 0.875],
"cubes": [
{"origin": [1.5, 47.5, 0], "size": [2, 1, 2], "inflate": 0.01, "uv": [44, 82]},
@@ -251,91 +255,6 @@
{"origin": [2.41, 46.4, 0.5], "size": [1, 1, 1], "inflate": 0.03, "uv": [39, 86]}
]
},
{
"name": "muzzle",
"parent": "head_angle",
"pivot": [-3, 48.5, -2],
"cubes": [
{"origin": [-2.5, 48, -2], "size": [5, 5, 2], "inflate": 0.02, "uv": [37, 31]},
{"origin": [-2, 51.48744, -3.03033], "size": [0, 1, 1], "inflate": 0.01, "pivot": [-2, 52.51777, -2], "rotation": [45, 0, 15], "uv": [43, 42]},
{"origin": [2, 51.48744, -3.03033], "size": [0, 1, 1], "inflate": 0.01, "pivot": [2, 52.51777, -2], "rotation": [45, 0, -15], "uv": [41, 42]}
]
},
{
"name": "locator_jaw_upper",
"parent": "muzzle",
"pivot": [0, 51.75, -2.25],
"rotation": [-90, 0, 0],
"locators": {
"jaw1": [0, 51.75, -2.25]
}
},
{
"name": "nose",
"parent": "muzzle",
"pivot": [0, 53, 0],
"rotation": [-40, 0, 0],
"cubes": [
{"origin": [-2.5, 51.36698, -1.67861], "size": [5, 2, 2], "inflate": 0.03, "uv": [48, 12]},
{"origin": [-2, 53.40698, -1.17861], "size": [4, 0, 1], "uv": [0, 15]}
]
},
{
"name": "jaw",
"parent": "head_angle",
"pivot": [0, 45.5, -2],
"cubes": [
{"origin": [-3.5, 45.5, -4], "size": [7, 3, 2], "inflate": 0.01, "uv": [76, 20]}
]
},
{
"name": "jaw2",
"parent": "jaw",
"pivot": [0, 48.5, -4],
"rotation": [-7.5, 0, 0],
"cubes": [
{"origin": [-2, 48.49, -4], "size": [4, 4, 2], "uv": [0, 51]},
{"origin": [-1.5, 48.5, -2], "size": [3, 4, 0], "uv": [90, 0]},
{"origin": [1.5, 51.49749, -3.03033], "size": [0, 1, 1], "pivot": [1.5, 52.52782, -2], "rotation": [45, 0, -7.5], "uv": [37, 39]},
{"origin": [-1.5, 51.49749, -3.03033], "size": [0, 1, 1], "pivot": [-1.5, 52.52782, -2], "rotation": [45, 0, 7.5], "uv": [37, 38]}
]
},
{
"name": "locator_jaw_lower",
"parent": "jaw2",
"pivot": [0, 51.75, -1.75],
"locators": {
"jaw2": {
"offset": [0, 51.75, -1.75],
"rotation": [-90, 0, 0]
}
}
},
{
"name": "tongue",
"parent": "jaw",
"pivot": [0, 45.5, -2],
"cubes": [
{"origin": [-1.5, 45.5, -2], "size": [3, 3, 0], "uv": [87, 29]}
]
},
{
"name": "tongue2",
"parent": "tongue",
"pivot": [0, 48.5, -2],
"cubes": [
{"origin": [-1, 48.5, -2], "size": [2, 2, 0], "inflate": 0.01, "uv": [46, 38]}
]
},
{
"name": "tongue3",
"parent": "tongue2",
"pivot": [0, 50.5, -2],
"cubes": [
{"origin": [-1, 50.5, -2], "size": [2, 1, 0], "uv": [37, 43]},
{"origin": [-0.5, 51.5, -2], "size": [1, 1, 0], "uv": [45, 43]}
]
},
{
"name": "horns",
"parent": "head_angle",
@@ -381,6 +300,72 @@
"horn2": [2.5, 39, 2]
}
},
{
"name": "nose",
"parent": "head_angle",
"pivot": [0, 53, 0],
"rotation": [-40, 0, 0],
"cubes": [
{"origin": [-2.5, 51.36698, -1.67861], "size": [5, 2, 2], "inflate": 0.03, "uv": [48, 12]},
{"origin": [-2, 53.40698, -1.17861], "size": [4, 0, 1], "uv": [0, 15]}
]
},
{
"name": "jaw",
"parent": "head_angle",
"pivot": [0, 45.5, -2],
"cubes": [
{"origin": [-3.5, 45.5, -4], "size": [7, 3, 2], "inflate": 0.01, "uv": [76, 20]}
]
},
{
"name": "jaw2",
"parent": "jaw",
"pivot": [0, 48.5, -4],
"rotation": [-7.5, 0, 0],
"cubes": [
{"origin": [-2, 48.49, -4], "size": [4, 4, 2], "uv": [0, 51]},
{"origin": [-1.5, 48.5, -1.99], "size": [3, 4, 0], "uv": [90, 0]},
{"origin": [1.5, 51.49749, -3.03033], "size": [0, 1, 1], "pivot": [1.5, 52.52782, -2], "rotation": [45, 0, -7.5], "uv": [37, 39]},
{"origin": [-1.5, 51.49749, -3.03033], "size": [0, 1, 1], "pivot": [-1.5, 52.52782, -2], "rotation": [45, 0, 7.5], "uv": [37, 38]}
]
},
{
"name": "locator_jaw_lower",
"parent": "jaw2",
"pivot": [0, 51.75, -1.75],
"locators": {
"jaw2": {
"offset": [0, 51.75, -1.75],
"rotation": [-90, 0, 0]
}
}
},
{
"name": "tongue",
"parent": "jaw",
"pivot": [0, 45.5, -2],
"cubes": [
{"origin": [-1.5, 45.5, -2], "size": [3, 3, 0], "uv": [87, 29]}
]
},
{
"name": "tongue2",
"parent": "tongue",
"pivot": [0, 48.5, -2],
"cubes": [
{"origin": [-1, 48.5, -2], "size": [2, 2, 0], "inflate": 0.01, "uv": [46, 38]}
]
},
{
"name": "tongue3",
"parent": "tongue2",
"pivot": [0, 50.5, -2],
"cubes": [
{"origin": [-1, 50.5, -2], "size": [2, 1, 0], "uv": [37, 43]},
{"origin": [-0.5, 51.5, -2], "size": [1, 1, 0], "uv": [45, 43]}
]
},
{
"name": "arms",
"parent": "torso2",
@@ -418,14 +403,6 @@
{"origin": [-21.5, 22, -1.5], "size": [3, 2, 3], "inflate": 0.1, "uv": [0, 58]}
]
},
{
"name": "locator_item",
"parent": "hand_right",
"pivot": [-21.6, 23, 0],
"locators": {
"item": [-21.6, 23, 0]
}
},
{
"name": "locator_hand_primary",
"parent": "hand_right",
@@ -936,14 +913,6 @@
{"origin": [0, 9.5, 58.5], "size": [0, 13, 7], "pivot": [0, 14.45, 62], "rotation": [0, 90, 0], "uv": [0, 92]}
]
},
{
"name": "locator_fire",
"parent": "fire2",
"pivot": [0, 11, 62],
"locators": {
"fire": [0, 11, 62]
}
},
{
"name": "legs",
"parent": "body",
@@ -976,10 +945,9 @@
{
"name": "locator_foot_primary",
"parent": "foot_right",
"pivot": [-9, 1.5, -5],
"rotation": [90, 0, 0],
"pivot": [-9, 1.5, -7],
"locators": {
"foot_primary": [-9, 1.5, -5]
"foot_primary": [-9, 1.5, -7]
}
},
{
@@ -1041,10 +1009,9 @@
{
"name": "locator_foot_secondary",
"parent": "foot_left",
"pivot": [9, 1.5, -5],
"rotation": [90, 0, 0],
"pivot": [9, 1.5, -7],
"locators": {
"foot_secondary": [9, 1.5, -5]
"foot_secondary": [9, 1.5, -7]
}
},
{
@@ -405,6 +405,14 @@
"cubes": [
{"origin": [-5, 6.5, 25.92], "size": [10, 3, 0], "uv": [77, 7]}
]
},
{
"name": "locator_seat_1",
"parent": "body",
"pivot": [0, 0, 0],
"locators": {
"seat_1": [0, 17.5, 4]
}
}
]
}
@@ -7,8 +7,8 @@
"texture_width": 128,
"texture_height": 128,
"visible_bounds_width": 6,
"visible_bounds_height": 4.5,
"visible_bounds_offset": [0, 1.75, 0]
"visible_bounds_height": 5,
"visible_bounds_offset": [0, 1.5, 0]
},
"bones": [
{
@@ -480,6 +480,14 @@
{"origin": [-4.5, 24.5, 26.5], "size": [9, 9, 7], "uv": [66, 109]}
]
},
{
"name": "locator_seat_1",
"parent": "torso",
"pivot": [0, 0, 0],
"locators": {
"seat_1": [0, 30, 0]
}
},
{
"name": "legs",
"parent": "body",
@@ -237,8 +237,16 @@
"cubes": [
{"origin": [10, 2, -1], "size": [2, 2, 2], "inflate": -0.001, "uv": [8, 36]}
]
},
{
"name": "locator_camera",
"parent": "tandemaus",
"pivot": [0, 0, 0],
"locators": {
"camera": [0, 0, 0]
}
}
]
}
]
}
}
@@ -601,8 +601,16 @@
"cubes": [
{"origin": [-2.33, -1, -2.65], "size": [2, 2, 2], "inflate": 0.02, "pivot": [-1.3, 0, -1.65], "rotation": [0, -45, 0], "uv": [52, 36], "mirror": true}
]
},
{
"name": "locator_camera",
"parent": "ceruledge",
"pivot": [0, 0, 0],
"locators": {
"camera": [0, 0, 0]
}
}
]
}
]
}
}
@@ -26,8 +26,13 @@
"pivot": [0, 4, 0]
},
{
"name": "arm_hammer_right",
"name": "arms_hammer",
"parent": "torso_hammer",
"pivot": [0, 7, 0]
},
{
"name": "arm_hammer_right",
"parent": "arms_hammer",
"pivot": [-1.5, 6.5, 0]
},
{
@@ -307,8 +312,13 @@
]
},
{
"name": "arm_left",
"name": "arms",
"parent": "torso",
"pivot": [0, 7, 0]
},
{
"name": "arm_left",
"parent": "arms",
"pivot": [1.5, 6.5, 0],
"cubes": [
{"origin": [1.5, 5.5, -1.5], "size": [3, 2, 3], "uv": [94, 16]}
@@ -369,7 +379,7 @@
},
{
"name": "arm_right",
"parent": "torso",
"parent": "arms",
"pivot": [-1.5, 6.5, 0],
"cubes": [
{"origin": [-4.5, 5.5, -1.5], "size": [3, 2, 3], "uv": [58, 93]}
@@ -459,8 +469,16 @@
"cubes": [
{"origin": [0.25, 0, -1], "size": [2, 2, 2], "inflate": 0.2, "uv": [38, 54]}
]
},
{
"name": "locator_camera",
"parent": "tinkaton",
"pivot": [0, 0, 0],
"locators": {
"camera": [0, 0, 0]
}
}
]
}
]
}
}
@@ -99,7 +99,14 @@
"poseTypes": ["FLY"],
"isBattle": false,
"condition": "!q.is_gliding",
"animations": ["q.look('head_ai')", "q.bedrock('charizard', 'air_fly')"],
"animations": [
"q.look('head_ai')",
"q.bedrock('charizard', 'air_fly')",
{
"condition": "q.is_ridden",
"animation": "q.bedrock('charizard', 'ride_air_look')"
}
],
"quirks": [
"q.bedrock_quirk('charizard', 'blink')",
"q.bedrock_quirk('charizard', 'air_fly_quirk')"
@@ -109,7 +116,14 @@
"poseTypes": ["FLY"],
"isBattle": false,
"condition": "q.is_gliding",
"animations": ["q.look('head_ai')", "q.bedrock('charizard', 'air_glide_TEST')"],
"animations": [
"q.look('head_ai')",
"q.bedrock('charizard', 'air_glide_TEST')",
{
"condition": "q.is_ridden",
"animation": "q.bedrock('charizard', 'ride_air_look')"
}
],
"quirks": [
"q.bedrock_quirk('charizard', 'blink')"
]
@@ -0,0 +1,63 @@
{
"portraitScale": 0.89,
"portraitTranslation": [-0.17,2.04,0],
"profileScale": 0.37,
"profileTranslation": [0,1.14,0],
"rootBone": "kangaskhan",
"animations": {
"cry": "q.bedrock_stateful('kangaskhan', 'cry')",
"recoil": "q.bedrock_stateful('kangaskhan', 'recoil')"
},
"poses": {
"battle-standing": {
"poseTypes": [
"STAND"
],
"isBattle": true,
"animations": [
"q.look('kid_head')",
"q.bedrock('kangaskhan', 'battle_idle')"
],
"quirks": [
"q.bedrock_quirk('kangaskhan', 'blink')"
]
},
"standing": {
"poseTypes": [
"STAND",
"NONE",
"PORTRAIT",
"PROFILE"
],
"isBattle": false,
"animations": [
"q.look('kid_head')",
"q.bedrock('kangaskhan', 'ground_idle')"
],
"quirks": [
"q.bedrock_quirk('kangaskhan', 'blink')"
]
},
"walking": {
"poseTypes": [
"WALK",
"SWIM"
],
"animations": [
"q.look('kid_head')",
"q.bedrock('kangaskhan', 'ground_walk')"
],
"quirks": [
"q.bedrock_quirk('kangaskhan', 'blink')"
]
},
"sleep": {
"poseTypes": [
"SLEEP"
],
"animations": [
"q.bedrock('kangaskhan', 'sleep')"
]
}
}
}
@@ -4,6 +4,18 @@
"profileScale": 0.28,
"profileTranslation": [ 0, 1.26, 0 ],
"rootBone": "tropius",
"seatToCameraOffset": {
"seat_1": [
0,
5,
10
],
"seat_1_reverse": [
0,
2,
4
]
},
"animations": {
"faint": "q.bedrock_primary('tropius', 'faint', q.curve('one'))",
"cry": "q.bedrock_stateful('tropius', 'cry')",
@@ -139,8 +139,7 @@
"poseTypes": ["FLY"],
"animations": ["q.look('head')", "q.bedrock('garchomp', 'air_fly')"],
"quirks": [
"q.bedrock_quirk('garchomp', 'blink')",
"q.bedrock_quirk('garchomp', q.array('air_fly_quirk1', 'air_fly_quirk2'), 5, 10, 1)"
"q.bedrock_quirk('garchomp', 'blink')"
],
"transformedParts": [
{
@@ -0,0 +1,36 @@
{
"portraitScale": 1.5,
"portraitTranslation": [-1.0, 1.76, 0.0],
"profileScale": 0.5,
"profileTranslation": [0.0, 1.0, 0.0],
"rootBone": "mudsdale",
"animations": {
"cry": "q.bedrock_stateful('mudsdale', 'cry')"
},
"poses": {
"sleep": {
"poseName": "sleep",
"poseTypes": ["SLEEP"],
"animations": ["q.bedrock('mudsdale', 'sleep')"]
},
"standing": {
"poseName": "standing",
"poseTypes": ["STAND", "FLOAT", "NONE", "PORTRAIT", "PROFILE"],
"animations": [
"q.look('head')",
"q.bedrock('mudsdale', 'ground_idle')",
"q.bedrock_stateful('mudsdale', 'blink')"
]
},
"walk": {
"poseName": "walk",
"poseTypes": ["WALK", "SWIM"],
"animations": [
"q.look('head')",
"q.bedrock('mudsdale', 'ground_walk')",
"q.bedrock_stateful('mudsdale', 'blink')"
]
}
}
}
@@ -1,28 +1,58 @@
{
"portraitScale": 1.7,
"portraitTranslation": [-0.07, 2.95, 0],
"profileScale": 0.33,
"profileTranslation": [0, 1.23, 0],
"rootBone": "cinderace",
"animations": {
"cry": "q.bedrock_stateful('cinderace', 'cry')"
},
"poses": {
"standing": {
"poseName": "standing",
"poseTypes": ["STAND", "FLOAT", "PORTRAIT", "PROFILE", "NONE"],
"animations": ["q.bedrock('cinderace', 'ground_idle')"],
"quirks": ["q.bedrock_quirk('cinderace', 'blink')"]
"portraitScale": 1.5,
"portraitTranslation": [-0.13, 2.74, 0],
"profileScale": 0.37,
"profileTranslation": [0, 1.22, 0],
"rootBone": "cinderace",
"animations": {
"faint": "q.bedrock_primary('cinderace', math.random(0, 1) < 0.25 ? 'faint2' : 'faint', q.curve('one'))",
"cry": "q.bedrock_stateful('cinderace', 'cry')",
"recoil": "q.bedrock_stateful('cinderace', 'recoil')",
"physical": "q.bedrock_primary('cinderace', 'physical', q.curve('symmetrical'))",
"special": "q.bedrock_primary('cinderace', 'special', q.curve('symmetrical'))",
"status": "q.bedrock_primary('cinderace', 'status', q.curve('symmetrical'))"
},
"walking": {
"poseName": "walking",
"poseTypes": ["WALK", "SWIM"],
"animations": [
"q.bedrock('cinderace', 'ground_idle')",
"q.biped_walk(0.66, 0.6, 'leg_left0', 'leg_right0')",
"q.bimanual_swing(0.66, 0.6, 'arm_left', 'arm_right')"
],
"quirks": ["q.bedrock_quirk('cinderace', 'blink')"]
"poses": {
"battle-standing": {
"poseTypes": ["STAND"],
"isBattle": true,
"animations": [
"q.look('head')",
"q.bedrock('cinderace', 'battle_idle')"
],
"namedAnimations": {
"cry": "q.bedrock_primary('cinderace', 'battle_cry', q.curve('one'))"
},
"quirks": ["q.bedrock_quirk('cinderace', 'blink')"]
},
"standing": {
"poseTypes": ["STAND", "NONE", "PORTRAIT", "PROFILE"],
"isBattle": false,
"animations": [
"q.look('head')",
"q.bedrock('cinderace', 'ground_idle')"
],
"quirks": [
"q.bedrock_quirk('cinderace', 'blink')"
],
"transitions": {
"battle-standing": "q.bedrock_primary('cinderace', 'battle_intro'), q.curve('symmetrical'))"
}
},
"walking": {
"poseTypes": ["WALK"],
"animations": [
"q.look('head')",
"q.bedrock('cinderace', 'ground_walk')"
],
"quirks": ["q.bedrock_quirk('cinderace', 'blink')"]
},
"sleeping": {
"poseTypes": ["SLEEP"],
"namedAnimations": {
"cry": "q.bedrock_stateful('dummy', 'cry')"
},
"animations": ["q.bedrock('cinderace', 'sleep')"]
}
}
}
}
}
@@ -1,17 +1,19 @@
{
"species": "cobblemon:kangaskhan",
"order": 0,
"variations": [
{
"aspects": [],
"poser": "cobblemon:kangaskhan",
"model": "cobblemon:kangaskhan.geo",
"texture": "cobblemon:textures/pokemon/0115_kangaskhan/kangaskhan.png",
"layers": []
},
{
"aspects": ["shiny"],
"texture": "cobblemon:textures/pokemon/0115_kangaskhan/kangaskhan_shiny.png"
}
]
}
"species": "cobblemon:kangaskhan",
"order": 0,
"variations": [
{
"aspects": [],
"poser": "cobblemon:kangaskhan",
"model": "cobblemon:kangaskhan.geo",
"texture": "cobblemon:textures/pokemon/0115_kangaskhan/kangaskhan.png",
"layers": []
},
{
"aspects": [
"shiny"
],
"texture": "cobblemon:textures/pokemon/0115_kangaskhan/kangaskhan_shiny.png"
}
]
}
@@ -7,11 +7,20 @@
"poser": "cobblemon:cinderace",
"model": "cobblemon:cinderace.geo",
"texture": "cobblemon:textures/pokemon/0815_cinderace/cinderace.png",
"layers": []
"layers": [
{
"name": "emissive",
"emissive": true,
"texture": "cobblemon:textures/pokemon/0815_cinderace/cinderace_emissive.png",
"translucent": true
}
]
},
{
"aspects": ["shiny"],
"aspects": [
"shiny"
],
"texture": "cobblemon:textures/pokemon/0815_cinderace/cinderace_shiny.png"
}
]
}
}
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "cobblemon:block/stadium_terminal"
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "cobblemon:block/stadium_terminal"
}
}
@@ -0,0 +1,3 @@
{
"parent": "cobblemon:block/stadium_terminal"
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/evolution/syrupy_apple"
}
}
@@ -1026,6 +1026,50 @@
{ "name": "cobblemon:shiny/wild_shiny_ambient_chime_4", "volume": 0.8, "attenuation_distance": 128.0 }
]
},
"animation.plumage.wing_flap.small": {
"sounds": [
{ "name": "cobblemon:animation/wings/plumage_wing_flap_small_1", "volume": 0.25 },
{ "name": "cobblemon:animation/wings/plumage_wing_flap_small_2", "volume": 0.25 },
{ "name": "cobblemon:animation/wings/plumage_wing_flap_small_3", "volume": 0.25 },
{ "name": "cobblemon:animation/wings/plumage_wing_flap_small_4", "volume": 0.25 },
{ "name": "cobblemon:animation/wings/plumage_wing_flap_small_5", "volume": 0.25 },
{ "name": "cobblemon:animation/wings/plumage_wing_flap_small_6", "volume": 0.25 },
{ "name": "cobblemon:animation/wings/plumage_wing_flap_small_7", "volume": 0.25 }
]
},
"animation.plumage.wing_flap.medium": {
"sounds": [
{ "name": "cobblemon:animation/wings/plumage_wing_flap_medium_1", "volume": 0.3 },
{ "name": "cobblemon:animation/wings/plumage_wing_flap_medium_2", "volume": 0.3 },
{ "name": "cobblemon:animation/wings/plumage_wing_flap_medium_3", "volume": 0.3 },
{ "name": "cobblemon:animation/wings/plumage_wing_flap_medium_4", "volume": 0.3 },
{ "name": "cobblemon:animation/wings/plumage_wing_flap_medium_5", "volume": 0.3 },
{ "name": "cobblemon:animation/wings/plumage_wing_flap_medium_6", "volume": 0.3 },
{ "name": "cobblemon:animation/wings/plumage_wing_flap_medium_7", "volume": 0.3 }
]
},
"animation.leather.wing_flap.small": {
"sounds": [
{ "name": "cobblemon:animation/wings/leather_wing_flap_small_1", "volume": 0.25 },
{ "name": "cobblemon:animation/wings/leather_wing_flap_small_2", "volume": 0.25 },
{ "name": "cobblemon:animation/wings/leather_wing_flap_small_3", "volume": 0.25 },
{ "name": "cobblemon:animation/wings/leather_wing_flap_small_4", "volume": 0.25 },
{ "name": "cobblemon:animation/wings/leather_wing_flap_small_5", "volume": 0.25 },
{ "name": "cobblemon:animation/wings/leather_wing_flap_small_6", "volume": 0.25 },
{ "name": "cobblemon:animation/wings/leather_wing_flap_small_7", "volume": 0.25 }
]
},
"animation.leather.wing_flap.medium": {
"sounds": [
{ "name": "cobblemon:animation/wings/leather_wing_flap_medium_1", "volume": 0.3 },
{ "name": "cobblemon:animation/wings/leather_wing_flap_medium_2", "volume": 0.3 },
{ "name": "cobblemon:animation/wings/leather_wing_flap_medium_3", "volume": 0.3 },
{ "name": "cobblemon:animation/wings/leather_wing_flap_medium_4", "volume": 0.3 },
{ "name": "cobblemon:animation/wings/leather_wing_flap_medium_5", "volume": 0.3 },
{ "name": "cobblemon:animation/wings/leather_wing_flap_medium_6", "volume": 0.3 },
{ "name": "cobblemon:animation/wings/leather_wing_flap_medium_7", "volume": 0.3 }
]
},
"pokemon.bulbasaur.ambient": {
"sounds": [ "cobblemon:pokemon/bulbasaur/bulbasaur_ambient" ]
},

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