Compare commits

..
Author SHA1 Message Date
Slippy 8b371127ed 1,000 files later... 2026-04-25 23:55:49 -05:00
Hiroku 8ee0d904ed Merge branch '1.21.1-TMs' into '1.8.0'
Merge TMs into 1.8 FINALLY

See merge request cable-mc/cobblemon!1853
2026-03-25 11:24:07 +00:00
Paul 291196eda7 Removed unused mixin 2026-03-25 20:30:07 +10:00
Hiroku b94e6d65b9 Merge branch '1.8.0' into '1.21.1-TMs'
# Conflicts:
#   CHANGELOG-1.8.md
#   common/src/main/kotlin/com/cobblemon/mod/common/pokemon/Pokemon.kt
#   common/src/main/kotlin/com/cobblemon/mod/common/world/feature/CobblemonFeatures.kt
2026-03-25 10:23:42 +00:00
jackowes 60fdd3325e remove duplicate registration 2026-03-22 17:26:41 -05:00
Paul eedcdafcbe Removed SpeciesLevel data file in favour of expanding the pokedex data 2026-03-22 14:46:44 +10:00
Paul 34595e01a9 Simplified some TM stuff 2026-03-21 22:33:29 +10:00
Paul 60b9ca7b7f Fixed a lol woopsy 2026-03-21 19:21:07 +10:00
Paul 83aea117c6 TM bits of cleanup and some fixes 2026-03-21 16:52:56 +10:00
Plastered_Crab 78b348329c Add more clusters to world genned type gem clusters 2026-03-17 19:17:35 -07:00
Plastered_Crab b64013c995 Type Gem Cluster world gen fix 2026-03-17 18:30:13 -07:00
Plastered_Crab 85003c9829 Get TM Unlocking on Level Up working again - Needs review 2026-03-17 14:12:53 -07:00
Plastered_Crab d9133e854a Clean up TM move sync 2026-03-17 13:13:04 -07:00
Plastered_Crab 05afe191e6 Add new textures for Data Monitor screens 2026-03-10 15:24:57 -07:00
Plastered_Crab e3b5067f31 Last Bug for the TM Machine squashed 2026-03-10 12:05:16 -07:00
Plastered_Crab bfa2d470f0 remove a few config checks 2026-03-10 11:34:47 -07:00
Plastered_Crab 53c0b28deb kill terablast 2026-03-10 11:33:59 -07:00
Plastered_Crab 5e9208d898 Fix small typos 2026-03-10 09:19:19 -07:00
Plastered_Crab 23a91ec2c9 Rescrape TMs to be current 2026-03-10 09:06:15 -07:00
Plastered_Crab 9998a328e3 Edit TM scraper 2026-03-10 09:02:38 -07:00
Plastered_Crab 9f07747cac Cleanup Obtainment methods for TMs 2026-03-10 09:02:22 -07:00
Plastered_Crab a7998bcec5 Cleanup Obtainment methods for TMs 2026-03-10 09:01:59 -07:00
Plastered_Crab 5983b29e9c Added Changelog 2026-03-09 17:54:39 -07:00
Plastered_Crab 749f441913 Merge branch 'main' into 1.21.1-TMs 2026-03-09 17:41:11 -07:00
Plastered_Crab dabbcceb9c Add Configs for having TMs be infinite use 2026-03-09 17:08:24 -07:00
Plastered_Crab 11f8313fc3 Add Configs for unlocking all TM and Level Up Moves and for Pokedex and TM Machine 2026-03-09 14:27:27 -07:00
Plastered_Crab 32b813620b Fix TM Machine Screen Back button to be more readable 2026-03-09 14:25:39 -07:00
Plastered_Crab 8147067b2e Fix Disk Rack West / East interaction 2026-03-09 08:39:31 -07:00
Plastered_Crab 24c6544e83 Sound Engine mixin to not have high octave pitches become flattened 2026-03-06 11:27:57 -08:00
Plastered_Crab b422ee4d29 Disk Jockeyyyyyyyy 2026-03-05 14:41:56 -08:00
Plastered_Crab a83867e153 When Data Monitor breaks it drops the stored disk, but not when moved by piston 2026-03-05 13:11:10 -08:00
Plastered_Crab 523973d2c0 Data monitor consumes the disk from player hand in Survival 2026-03-05 12:47:43 -08:00
Plastered_Crab 746160fa18 Disk Shelf works with Comparators and output a signal based on how many slots are filled 2026-03-05 12:06:05 -08:00
Plastered_Crab 837ba9679b Fix inverted columns and interaction with Disk Shelf 2026-03-05 11:35:33 -08:00
Plastered_Crab db7a319441 Invert Hopper interaction slots and storage array index 2026-03-05 11:00:14 -08:00
Plastered_Crab e284032c7e Give TM command allows for specifying quantity now 2026-03-05 10:05:17 -08:00
Plastered_Crab 3db9dd02f2 Disk Shelf works with Hoppers now 2026-03-05 08:54:30 -08:00
Plastered_Crab e680ec8790 If TM Shelf gets destroyed it drops stored disks 2026-03-04 16:05:57 -08:00
Plastered_Crab dc4f831e02 Fix slot interaction zones in North and South directions 2026-03-04 15:44:42 -08:00
Plastered_Crab b3a00c40b5 Adjust Slot brightness for Disk Shelf 2026-03-04 15:18:50 -08:00
Plastered_Crab f56fb0f50a Add new assets for TM Shelf disks 2026-03-04 14:27:12 -08:00
Plastered_Crab ec732bc03d Fix alignment issues and Lighting issues for TM Shelf 2026-03-04 13:42:43 -08:00
Plastered_Crab 229abd4a13 Fix lighting on rendered slot items 2026-03-04 11:46:18 -08:00
Plastered_Crab 7e92c17178 Fix WIP assets for TM Shelf disks 2026-03-04 11:17:21 -08:00
Plastered_Crab 77aa3208a0 Fix interaction zones on TM Shelf 2026-03-04 10:14:47 -08:00
Plastered_Crab b2ea715195 Update with main and add new Type Gem assets 2026-03-02 12:49:17 -08:00
Polymeta 35e4aafe99 Merge branch 'main' into 1.8.0 2026-02-26 15:46:01 +00:00
Plastered_Crab eab6fa9b40 Merge branch 'main' into 1.21.1-TMs 2026-02-25 13:43:40 -08:00
Plastered_Crab 98de423f91 Add giveTM command 2026-02-14 01:22:15 -08:00
Paul ef4fbecad6 Merge remote-tracking branch 'origin/1.8.0' into 1.8.0 2026-02-14 14:30:41 +10:00
Paul 96075ed34a Merge remote-tracking branch 'origin/main' into 1.8.0 2026-02-14 14:30:11 +10:00
Plastered_Crab e7cd9237f6 Have Move Dex only show Level Up, TM, and Egg moves 2026-02-13 19:43:49 -08:00
Plastered_Crab 84e22c68c7 Add white background for move list area on move Dex and add lang tooltips for filters 2026-02-13 19:16:36 -08:00
Plastered_Crab 300f2fc53c Add new type symbols, add dividing line 2026-02-13 15:43:18 -08:00
Plastered_Crab 2dfb88467b Added new filters to the Pokedex. More work on showing undiscovered/discovered level up moves per species in Move Dex 2026-02-13 13:45:56 -08:00
Plastered_Crab 589aab3b1a Move Dex adjustments 2026-02-13 11:50:27 -08:00
Plastered_Crab e17ca3a422 Clean up some of the Move Dex text 2026-02-13 11:07:58 -08:00
Plastered_Crab 0153846c7b Moves in Move Dex are hidden per species until discovered 2026-02-13 10:37:21 -08:00
Plastered_Crab f598f8d645 Secondary sorting for Move Dex 2026-02-12 21:03:48 -08:00
Plastered_Crab 8e3e047646 EVEN MORE Progress on the Move Dex 2026-02-12 19:28:40 -08:00
Plastered_Crab 551858df57 MORE Progress on the Move Dex 2026-02-12 14:42:39 -08:00
Plastered_Crab a7e3f4a7a1 Progress on the Move Dex 2026-02-12 11:15:52 -08:00
Plastered_Crab 94d64bb5c6 Progress on the Move Dex 2026-02-12 08:36:06 -08:00
Plastered_Crab e569acc648 Merge remote-tracking branch 'origin/1.21.1-TMs' into 1.21.1-TMs
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonNetwork.kt
2026-02-11 13:58:05 -08:00
Plastered_Crab 7c374b6e29 Tweaks to proceed with main merge to TMs 2026-02-11 13:56:22 -08:00
Plastered_Crab 3c128d9009 Merge branch 'main' into 1.21.1-TMs
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonNetwork.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/storage/player/GeneralPlayerData.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/storage/player/adapter/PlayerDataJsonBackend.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/storage/player/adapter/PlayerDataMongoBackend.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/storage/player/client/ClientGeneralPlayerData.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/CobblemonClient.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/gui/toast/CobblemonToast.kt
2026-02-11 13:40:44 -08:00
Plastered_Crab f5321a34c3 Merge branch 'main' into 1.21.1-TMs
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonNetwork.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/storage/player/GeneralPlayerData.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/storage/player/adapter/PlayerDataJsonBackend.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/storage/player/adapter/PlayerDataMongoBackend.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/storage/player/client/ClientGeneralPlayerData.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/CobblemonClient.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/gui/toast/CobblemonToast.kt
2026-02-11 12:23:37 -08:00
Plastered_Crab 2754bfc525 Data Monitor ejects disk out from monitor correctly 2026-02-09 09:02:49 -08:00
Plastered_Crab 3d1aecce13 Data Monitor to eject disk outwards and also unlock TM upon ejection 2026-02-09 00:30:31 -08:00
Plastered_Crab 38cd081ad6 Data Monitor to eject disk if player interacts with empty hand or non-disk item 2026-02-04 13:50:57 -08:00
Plastered_Crab 54a14ab805 Add new TM sync from move function for better performance when checking newly learned moves. 2026-02-04 13:49:37 -08:00
Plastered_Crab 633b45287c Sync TM moves upon new move added to a pokemon, and remove redundant sync checks on evolve and level up. 2026-02-04 13:36:28 -08:00
Plastered_Crab 3619f42090 Changes to Fossil machine Multi block to eject disks if the data monitor with one inserted becomes a Fossil Machine 2026-02-03 20:26:39 -08:00
Plastered_Crab 695453ffdb Changes to data monitor to allow disks to be placed inside to change the screen to learn TMs and change the screen texture 2026-02-03 20:25:09 -08:00
Polymeta 3c2bf0e2b3 Merge branch 'cobblemon-structure' into '1.8.0'
Slippy can Cook now!

See merge request cable-mc/cobblemon!2144
2026-01-30 09:45:31 +00:00
AramandPolymeta ac695b1092 Slippy can Cook now! 2026-01-30 09:45:31 +00:00
Plastered_Crab dd7066e8fa Sync New Tms after Level Up and Evolving 2026-01-29 12:34:08 -08:00
Plastered_Crab 416f003927 Remove debugging from Type Gem clusters 2026-01-29 10:44:13 -08:00
Plastered_Crab 3be3dc3de2 Add TM Data Sync upon login via scheduled task 2026-01-29 10:43:29 -08:00
Plastered_Crab a8f273737d Fix all default unlocked TMs 2026-01-26 12:41:02 -08:00
Plastered_Crab a185805b3f Fix scraper to scrape locked vs default TMs properly 2026-01-26 12:40:10 -08:00
Plastered_Crab defab6eaff Brief edit to TM scraper to properly scrape default TMs 2026-01-26 12:29:39 -08:00
Plastered_Crab 72fc1f1fb9 Fix the visual stage of the Type Gem Cluster Item Entity when dropped (with silk touch for example) 2026-01-26 11:53:58 -08:00
Plastered_Crab f96c69ab54 Unlock TMM recipe when interacting with the TMM without knowing the recipe 2026-01-26 11:48:08 -08:00
Plastered_Crab d51039dbb8 Merge branch 'main' into 1.21.1-TMs
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/client/CobblemonClient.kt
#	common/src/main/resources/data/minecraft/tags/block/mineable/pickaxe.json
2026-01-26 10:21:42 -08:00
Polymeta f450d9d2d6 Merge branch 'fix-bucket-reuse' into '1.8.0'
Fixed multi-spawns in a single pass using the same bucket for all of them

See merge request cable-mc/cobblemon!2104
2026-01-22 13:21:39 +00:00
Paul 0752ab3cac Fixed woopsies in changelog 2026-01-22 22:23:01 +10:00
Hiroku fe35a63769 Merge branch 'complex-movesets' into '1.8.0'
Complex movesets, parties, and pools

See merge request cable-mc/cobblemon!2086
2026-01-19 04:09:56 +00:00
Guilherme Pereira 17cab186d9 Merge branch '1.21.1-TMs' of gitlab.com:cable-mc/cobblemon into 1.21.1-TMs 2026-01-14 16:09:42 -03:00
Guilherme Pereira e00136052d add python tm scraping script and add support for tags in tm recipes 2026-01-14 16:09:18 -03:00
Plastered_Crab b23237ca9a Merge branch 'main' into 1.21.1-TMs 2026-01-14 10:32:32 -08:00
Paul 95d238ada0 Fixed multi-spawns in a single pass using the same bucket for all of them 2026-01-02 22:38:46 +10:00
plastered_crab 36456bfb0d Merge branch 'main' into 1.21.1-TMs 2025-12-28 14:35:43 -08:00
plastered_crab d9661c356f Merge remote-tracking branch 'origin/1.21.1-TMs' into 1.21.1-TMs 2025-12-28 14:31:38 -08:00
Test a66fad69cf idle screen 2025-12-23 22:26:37 -05:00
Test 95488ac54b Merge branch '1.21.1-TMs' of https://gitlab.com/cable-mc/cobblemon into 1.21.1-TMs 2025-12-23 16:19:12 -05:00
Test 19f2b71273 idle screen 2025-12-23 16:18:43 -05:00
Guilherme Pereira ba6e136a0b add fabric data generator, move gem blocks loot tables from code to jsons 2025-12-23 14:55:10 -03:00
Guilherme Pereira 28ac437987 gem blocks shenanigans 2025-12-22 16:42:27 -03:00
Plastered_Crab a4935f19bb TMs with the "none" obtainment method are shown in the TM Machine by default 2025-12-21 18:17:26 -08:00
plastered_crab c3e470f1de Merge branch 'main' into 1.21.1-TMs 2025-12-20 20:41:59 -08:00
Plastered_Crab 4139337f85 Remove Batch TM button, but make it so Batching TMs works via redstone signal now. 2025-12-19 09:09:47 -08:00
Plastered_Crab 25bc2dea93 Merge remote-tracking branch 'origin/1.21.1-TMs' into 1.21.1-TMs 2025-12-18 15:23:19 -08:00
Plastered_Crab 9dc3884ea6 Modify and enhance TM Machine Automation batch processes 2025-12-18 15:22:57 -08:00
Guilherme Pereira 89d95c6ab8 Merge branch '1.21.1-TMs' of gitlab.com:cable-mc/cobblemon into 1.21.1-TMs 2025-12-18 18:30:30 -03:00
Guilherme Pereira 7b70aa5a1e add /technicalmachine check command 2025-12-18 18:30:18 -03:00
Plastered_Crab 8191b4d9b6 fix Thunder TM recipe 2025-12-18 09:21:02 -08:00
Guilherme Pereira 84534fd041 add /technicalmachine command 2025-12-17 18:06:03 -03:00
Guilherme Pereira e6e1446eb1 merge all tm toasts into one if a player learn more than one tm at once 2025-12-16 21:01:47 -03:00
plastered_crab 39fbadc4fb Can Silk Touch Type Gem clusters of all stages now 2025-12-15 15:28:12 -08:00
plastered_crab 3c2a9c1dfd Overhaul of the Type Gem Core block growth system (hopefully more performant too) 2025-12-15 15:05:11 -08:00
plastered_crab 921fcbe477 Fix TM Machine and Blank TM recipe unlocks 2025-12-15 13:58:37 -08:00
plastered_crab c90b6c86ab Type Gems and Type Gem Clusters can be placed on any surface for decoration 2025-12-15 13:00:48 -08:00
plastered_crab 3ecf25502b Remove old recipes and add new recipes for Type gem things 2025-12-15 12:54:09 -08:00
plastered_crab b808112e17 Type Gem clusters can be silk touched to decorate with their various stages 2025-12-15 12:29:06 -08:00
plastered_crab 1b2d31db03 Pistons break the Type Gem Clusters to give the right amount of Type Gems 2025-12-15 12:09:07 -08:00
plastered_crab c9f8445d14 Fortune enchantment affects drops from Type Gem cluster blocks and type gem blocks 2025-12-15 12:03:35 -08:00
plastered_crab acd879ebef Alter Type Gem Clusters to drop new amount of type gems based on growth stage 2025-12-15 11:34:25 -08:00
plastered_crab f6889fd8ea Change TypeGemCoreBlock max connected gems before going dormant to 7 2025-12-15 11:25:08 -08:00
plastered_crab 21ccbef6c9 Fix TM Machine and Blank TM recipe to unlock after getting an Amethyst Shard 2025-12-15 11:16:11 -08:00
plastered_crab 9349e6a668 Fix TM Machine recipe 2025-12-15 11:12:27 -08:00
plastered_crab 28a7fe6a04 Marge Main to TM Branch 2025-12-15 11:07:44 -08:00
plastered_crab 18e1ed79ef Merge branch 'main' into 1.21.1-TMs
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonNetwork.kt
#	common/src/main/resources/assets/cobblemon/lang/en_us.json
2025-12-15 10:56:51 -08:00
Paul aafdb7688a Added more molang expressions to a bunch of composed pool properties, fixed some bugs 2025-12-15 14:22:59 +10:00
Paul 73b53f9702 Added egg move selector 2025-12-15 12:07:06 +10:00
Paul 33317a57c7 more doco changes [skip-ci] 2025-12-14 20:33:34 +10:00
Paul 72d8f26cdb Change silly default example weight to the actual default weight 2025-12-14 20:27:30 +10:00
Paul aea1afe145 Rearrange doco 2025-12-14 20:26:21 +10:00
Paul 0fec45b7ea Added npcAspects condition for party pool entries 2025-12-14 20:24:52 +10:00
Paul af98b823aa Documentation 2025-12-14 20:13:04 +10:00
Paul 07d9da2ca9 Added last_suitable_offensive move selector, added alpha moveset builder 2025-12-14 17:29:47 +10:00
Paul c2c86b2ef1 Stack all the cobblemon:move_weights.json from any datapacks onto one big map, like tags 2025-12-14 17:05:58 +10:00
Paul 22733e7117 Added more advanced moveset and party construction for NPCs 2025-12-08 19:31:48 +10:00
plastered_crab 117afcea32 Merge remote-tracking branch 'origin/1.21.1-TMs' into 1.21.1-TMs
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonBlocks.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonNetwork.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/types/ElementalTypes.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/data/CobblemonDataProvider.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/pokemon/evolution/controller/ClientEvolutionController.kt
2025-11-21 19:45:56 -08:00
plastered_crab 3f89750ee5 Merge main to TM Branch 2025-11-21 19:43:35 -08:00
plastered_crab d88be7ae05 Merge branch 'main' into 1.21.1-TMs
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonBlocks.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonItemComponents.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonNetwork.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/types/ElementalTypes.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/data/CobblemonDataProvider.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/item/group/CobblemonItemGroups.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/world/feature/CobblemonPlacedFeatures.kt
2025-11-21 19:32:38 -08:00
Nadja Reitzenstein 24245331db Merge branch 'main' into 1.21.1-TMs
* main: (322 commits)
  changes to /npcdelete uuid prameter and console support
  Translated using Weblate (Japanese)
  Translated using Weblate (Japanese)
  Enforce minimum depth requirement for swim wander, fix mistake in omnipathnav
  Remember the last camera type used for a mount type and switch to it if the config is enabled
  Wait that wasn't meant to still be in there
  API and config and controller options for infinite stamina
  rm unused function
  fix stat color
  Removed an unused sound from sounds.json
  Migrated all the other controllers to support the global config
  Migrate global ride controller settings to use a different solution
  Added global controller settings for riding, moved jet over to it
  add pokémon fullness to pokémon properties
  fix poke puff tooltip and mild multiplier #1711 #1710
  Add offset setting for determining surface level
  Change sprint modifier expression, adjust acceleration formula
  Change how reloadability is checked for /reload, maybe this will fix server stuff
  Persist stamina between dismount and mount
  rm unused imports
  ...
2025-10-01 12:15:20 +02:00
Nadja Reitzenstein d6d10d33e3 Fix file licenses 2025-09-19 18:11:16 +02:00
Nadja Reitzenstein 4d88c9b383 Fix small typos 2025-09-19 17:07:26 +02:00
Nadja Reitzenstein a3f597c589 Minimise the Gitlab-shown diff by undoing formatting changes
This commit will *absolutely* be reverted before we merge, but it helps with reviewing because gitlab doesn't filter whitespaces changes well.
2025-09-19 17:07:26 +02:00
Nadja Reitzenstein 2a3d88c12e Remove stray println 2025-09-19 16:33:44 +02:00
dhi_holoandNadja Reitzenstein 9561f47337 Small Asset Updates
(cherry picked from commit 4bfca0da43)
2025-09-19 16:28:04 +02:00
Nadja Reitzenstein f02c92db22 Merge branch 'main' into 1.21.1-TMs
* main: (62 commits)
  tweak default stat ranges for some flying behaviours
  Added math.sign and math.copy_sigh molang dep update
  Grain Improvements
  update fabric-permissions-api to 0.3.1
  Behaviour tweaks
  Update mochis.json
  IV Drip
  Ride settings editor
  Fix in air dismount
  Fix riding waterwalk
  swap out textures
  Remove unnecessary check on resource
  Changelog [skip-ci]
  Forgor camera offsets for extra seats
  Bronzong ready to scrape.
  Fix double lid on campfire pot open sprites
  Rename CookingPotColor to CampfirePotColor
  Add color property in CampfirePotItem
  Sync cooking pot button color with open / closed state
  Add cooking pot open sprites
  ...
2025-09-19 15:44:49 +02:00
Nadja Reitzenstein 181ef5d50e No-Fixes and formatting 2025-09-19 14:26:31 +02:00
plastered_crab 870397ebb9 Merge branch 'main' into 1.21.1-TMs
# Conflicts:
#	common/src/main/resources/assets/cobblemon/lang/en_us.json
2025-09-08 21:30:19 -07:00
plastered_crab 0ed413070d Merge branch 'main' into 1.21.1-TMs 2025-08-25 21:58:27 -07:00
plastered_crab f66f5ffdf9 Get TMs up to date with main 2025-08-16 20:01:12 -07:00
plastered_crab ca280a7b3e Merge branch 'main' into 1.21.1-TMs
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonBlocks.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/CobblemonClient.kt
2025-08-16 19:45:45 -07:00
plastered_crab 85284bff9d Get TMs up to date with main 2025-08-10 17:01:53 -07:00
plastered_crab fa4d33f725 Merge branch 'main' into 1.21.1-TMs
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/api/types/ElementalTypes.kt
2025-08-10 16:55:57 -07:00
plastered_crab 4ce42cdf6d edits to ElementalType.kt 2025-07-29 17:12:14 -07:00
plastered_crab 1b8562ead8 edits to ElementalType.kt 2025-07-29 16:09:25 -07:00
plastered_crab b9d9b906fb Merge branch 'main' into 1.21.1-TMs
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/api/pokemon/moves/Learnset.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/types/ElementalType.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/CobblemonClient.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/item/group/CobblemonItemGroups.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/world/feature/CobblemonPlacedFeatures.kt
2025-07-29 08:36:31 -07:00
plastered_crab e9d079a223 Chance to add type gem clusters to works genned Type Gem growths underground 2025-07-09 23:03:13 -07:00
plastered_crab e2e42ee91c Chance to add type gem clusters to works genned Type Gem growths underground 2025-07-09 13:16:56 -07:00
plastered_crab 4b0208201b Chance to add type gem clusters to works genned Type Gem growths underground 2025-07-09 07:19:53 -07:00
plastered_crab bec3f97733 Fix some classes 2025-07-09 06:40:24 -07:00
plastered_crab 16cfe37dac Merge branch 'refs/heads/main' into 1.21.1-TMs
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonNetwork.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/CobblemonClient.kt
#	common/src/main/resources/assets/cobblemon/lang/en_us.json
2025-07-09 05:25:07 -07:00
plastered_crab 7381da863c Merge branch 'refs/heads/main' into 1.21.1-TMs 2025-06-29 20:55:28 -07:00
Test b0902825fa teach through drag-dropping in TMM 2025-06-27 01:34:45 -04:00
Test 31c489cba0 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into 1.21.1-TMs 2025-06-25 23:30:29 -04:00
Test 6a2f21d75a merge 2025-06-25 23:30:12 -04:00
Test e2c42a57c7 Merge branch '1.21.1-TMs' of https://gitlab.com/cable-mc/cobblemon into 1.21.1-TMs
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonBlocks.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/CobblemonClient.kt
2025-06-25 22:48:43 -04:00
Test 8592b53216 tmm refactor 2025-06-25 22:39:42 -04:00
plastered_crab 49dcf0049f Merge branch 'refs/heads/main' into 1.21.1-TMs
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonBlocks.kt
2025-06-20 06:08:06 -07:00
plastered_crab 076bee923f Merge branch 'refs/heads/main' into 1.21.1-TMs
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonBlocks.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonItemComponents.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonMenuType.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/CobblemonClient.kt
2025-06-10 18:27:00 -07:00
Plastered_Crab aacdb33827 Nevemind put it here instead 2025-05-30 10:17:02 -07:00
Plastered_Crab 53e9ece930 Player's TM datastore gets synced when their pokemon learn a move 2025-05-30 10:13:08 -07:00
plastered_crab 87f08d9bab 75% saturation on the Type colors 2025-05-29 23:43:01 -07:00
plastered_crab a50a6326af Merge remote-tracking branch 'origin/1.21.1-TMs' into 1.21.1-TMs 2025-05-29 22:32:12 -07:00
plastered_crab 3c0eec833e Type Color and TM asset change 2025-05-29 22:31:27 -07:00
Plastered_Crab 5b0cfdffcb Merge branch 'main' into 1.21.1-TMs 2025-05-29 15:11:22 -07:00
plastered_crab d788e0402e Merge remote-tracking branch 'origin/1.21.1-TMs' into 1.21.1-TMs 2025-05-28 19:04:22 -07:00
Plastered_Crab a347dc5e2a Merge branch 'main' into 1.21.1-TMs 2025-05-28 10:52:13 -07:00
plastered_crab b2fe158a7b Merge branch 'refs/heads/main' into 1.21.1-TMs 2025-05-28 09:33:57 -07:00
plastered_crab faab7e8df0 Change type gem block smelting recipes 2025-05-27 23:22:37 -07:00
plastered_crab 9070e198f1 Type gem clusters are no longer items and can't be placed. 2025-05-27 23:05:14 -07:00
plastered_crab 45b2a0db4d alter type gem clusters to drop type gems when broken 2025-05-27 21:51:16 -07:00
plastered_crab 65d39050ea Merge branch 'refs/heads/main' into 1.21.1-TMs
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonItemComponents.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonNetwork.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/CobblemonClient.kt
#	common/src/main/resources/assets/cobblemon/lang/en_us.json
#	common/src/main/resources/assets/cobblemon/sounds.json
2025-05-27 19:57:54 -07:00
plastered_crab 5da16df5ae Changes to Type Gem Cluster logic 2025-05-20 23:41:42 -07:00
plastered_crab 24fc4b05ab Toast appears now when learning a new TM + Licenses 2025-05-20 22:27:44 -07:00
Plastered_Crab 173902feb1 Starting code to display Toasts when unlocking new TMs 2025-05-20 19:14:41 -07:00
Plastered_Crab fd5f08fe84 Call syncTMsFromPokemon from add method in PokemonStore class. 2025-05-20 18:46:56 -07:00
Plastered_Crab d430ad6ca1 Move the syncTMsFromPokemon method to TMMoveManager 2025-05-20 18:21:05 -07:00
Plastered_Crab 1309c18292 Player unlocks TMs by catching pokemon with those moves and TM Machine lists only player learned moves 2025-05-20 18:08:42 -07:00
plastered_crab b6deebac97 Preparing for TM Move Data store 2025-05-19 15:16:01 -07:00
Plastered_Crab 83711f2dcb Merge branch '1.21.1-TMs-(dont-be-shelvish)' into 1.21.1-TMs
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/client/CobblemonClient.kt
2025-04-24 14:11:35 -07:00
Plastered_Crab 18e1a767af Use new TM Shelf Block and starting to get it working 2025-04-24 14:07:38 -07:00
Polymeta 6ae3efb461 fix merge and tidy up
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-04-24 19:29:38 +01:00
Polymeta 84e1934134 Merge branch 'refs/heads/main' into 1.21.1-TMs
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonBlockEntities.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonBlocks.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonItemComponents.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/CobblemonClient.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/data/CobblemonDataProvider.kt
#	common/src/main/resources/assets/cobblemon/lang/en_us.json
#	common/src/main/resources/cobblemon-common.accesswidener
#	fabric/src/main/kotlin/com/cobblemon/mod/fabric/CobblemonFabric.kt
2025-04-24 16:58:20 +01:00
Plastered_Crab 9aed9342ee Fix atrocious formatting 2025-04-23 13:33:54 -07:00
Plastered_Crab e4d0bf39ca Added in WIP tooltips for TMs 2025-04-23 13:26:32 -07:00
plastered_crab 847fa6842e Test Bookcase can hold TMs, Upgrade, Dubious Disc, Pokedex, etc (very WIP) 2025-04-22 13:51:15 -07:00
plastered_crab 08aa4f29bd Dubious Disc and Upgrade able to be placed in the Bookshelf too 2025-04-22 10:59:35 -07:00
plastered_crab 539218381b Corrected face being mirrored 2025-04-22 09:21:45 -07:00
plastered_crab 9dff39b4d7 Shelf is no longer upside down lmao 2025-04-22 08:42:24 -07:00
plastered_crab 1e578e94e5 Shelf renders without redish color 2025-04-22 08:32:35 -07:00
plastered_crab ec35c9b9bb shelf face rendered (upside down...) 2025-04-22 07:55:36 -07:00
plastered_crab 0deaeaeb7d fit the TM case textures onto shelves better 2025-04-22 07:22:49 -07:00
plastered_crab ec3d9e1a56 Test code for placing TMs in Chiseled Bookshelves 2025-04-21 17:11:10 -07:00
Polymeta 814f84ae42 licenses
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-04-18 01:11:33 +01:00
Polymeta 904be475ef Merge branch 'refs/heads/main' into 1.21.1-TMs
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonNetwork.kt
#	common/src/main/resources/cobblemon-common.accesswidener
2025-04-18 00:44:25 +01:00
Plastered_Crab 5edecbe81b Add crafting recipes / loot tables type gems, fix collision boxes, break rules, etc 2025-04-17 15:29:42 -07:00
Plastered_Crab f357033404 Fixed 100+ recipes, fixed CraftTMPacketHandler, adjusted GUI for TM Machine, and fixed names for some moves 2025-04-17 12:27:54 -07:00
Plastered_Crab 4800ae6649 Tweaking of some TM recipes 2025-04-17 09:29:21 -07:00
plastered_crab 60b0690c1e Add remaining 10 TM recipes. now all are present for testing 2025-04-17 00:40:00 -07:00
plastered_crab 82e31dd766 Add 330+ TM recipes for testing >:) 2025-04-17 00:00:34 -07:00
Guilherme Pereira 130e767e75 force type gems to grow halfway upon world generation 2025-03-28 05:02:33 -03:00
Guilherme Pereira b1a1d509ec make type gems grow naturally 2025-03-27 19:37:46 -03:00
Plastered_Crab 0698cf495e Type Gem Clusters fill in empty space when they grow grow stunted buds when hitting max capactity 2025-03-26 16:49:00 -07:00
Plastered_Crab 6047660405 Type Gem clusters grow in the same direction as their previous state more often and also fill in gaps with clusters 2025-03-26 14:53:05 -07:00
Plastered_Crab aaf3495f83 New transitional stages for the type gem clusters and fixes for rendering issues 2025-03-26 13:09:59 -07:00
Plastered_Crab ae6529c9fd Type gem clusters grow their respective type gem blocks when placed on the core 2025-03-25 17:05:03 -07:00
plastered_crab 45a96b2a42 Prepare for new Type Gem generation for each type of gem 2025-03-19 16:07:58 -07:00
Apion 4212903c67 Merge branch 'fix-tm-automation' into '1.21.1-TMs'
General Fixes and Implementation of the TM Machine for 1.21.1

See merge request cable-mc/cobblemon!1542
2025-03-01 08:52:01 +00:00
BuildTools be47dbcede Some Requested Changes 2025-03-01 06:05:38 +02:00
Apion 9556c57c69 Fix broken accesswideners 2025-02-23 21:33:54 -08:00
BuildTools f72b65bfac Fix for TMM GUI elements being offset in wrong postion after a previus TMM GUI Fix 2025-02-22 13:13:28 +02:00
BuildTools 6121700c9b Fixed disk in TMM rendering in wrong location after fixing TMM rendering backwards 2025-02-22 12:20:52 +02:00
BuildTools 91c968e743 A better fix for a previos TMM GUI fix 2025-02-22 12:05:30 +02:00
BuildTools 8fed6f4823 Fixed TMM rendering backwards and now the TMM will eject disc from its facing direction proper 2025-02-22 10:31:43 +02:00
BuildTools 34e4b39d75 Added Properties to TMM regarding breaking the block and loot table (based of PC) 2025-02-22 09:52:58 +02:00
BuildTools a21c70ce46 Resizing TMM GUI no longer breaks the GUI Buttons 2025-02-21 23:00:52 +02:00
BuildTools 8865a71f4c TMM will now output signal when ready to craft Blank TM and will drop Filter TM on break 2025-02-21 20:32:52 +02:00
BuildTools 142cadc187 TMM can now craft blank TMs if no TM is set in the filter, as well as allow taking out the filter TM 2025-02-21 19:43:36 +02:00
BuildTools 66f4c2531d Fixed TMM GUI quick move feature to properly work as well as what is considered to be outside the GUI 2025-02-19 20:16:00 +02:00
BuildTools 3f8ddd5f7d TM Machine now turns on/off and plays sound then opened/closed 2025-02-16 22:09:07 +02:00
BuildTools c076e14cbd Made Comparator read TM Machine and it provides power if the TM Machine has the materials to autocraft 2025-02-15 23:00:32 +02:00
BuildTools d724eb068b Fixed missing tooltip render call causing tooltips over items not showing in TM Machine 2025-02-15 13:10:15 +02:00
BuildTools d3ac263e29 Made the item form of TM Machine render properly in usual cases 2025-02-15 12:32:35 +02:00
BuildTools a6b7fe1f17 TM can now finally autocraft TMs based on filtered TM by receiving redstone signal 2025-02-15 09:50:28 +02:00
BuildTools ec714ccb84 Fixed Filtering for Hopper input not working 2025-02-12 19:53:54 +02:00
BuildTools ab0a129ba1 TM Machine GUI and Inventory synced and working properly 2025-02-12 18:45:32 +02:00
Guilherme Pereira a3f272b2aa Merge branch 'main' into 1.21.1-TMs 2025-02-06 03:48:28 -03:00
Guilherme Pereira 77d91ed979 make last type gems growing from core not fully grow into blocks 2025-01-29 03:56:35 -03:00
Guilherme Pereira 9907ba17c1 update licenses 2025-01-27 06:28:51 -03:00
Guilherme Pereira a6f0e19a44 type gem core now generates more gems 2025-01-27 06:27:27 -03:00
Guilherme Pereira 7ee064b04d make type gem bud grow into a block in its final stage 2025-01-27 05:29:14 -03:00
Guilherme Pereira f2e4c735f7 add type gems 2025-01-27 05:04:04 -03:00
Guilherme Pereira 5345bd321f update licenses 2025-01-21 19:08:49 -03:00
Guilherme Pereira eab8d0063b fix tms item sprite colors 2025-01-21 19:08:00 -03:00
Guilherme Pereira 6877977234 tm branch ressurect attempt 2025-01-17 23:23:01 -03:00
plastered_crab 60cb81362e Added some small langs 2025-01-09 07:46:53 -08:00
plastered_crab 088acb8e86 Added TMs, created TechnicalMachineRegistrySyncPacket.kt, TM json files are loading, TM machine GUI working better, altered obtain methods, and more 2025-01-08 20:04:24 -08:00
plastered_crab 77f59f06cb add tm_disk.geo file 2025-01-08 10:49:41 -08:00
plastered_crab a0882c6105 TM branch lives to see another day! (Still needs some issues fixed) 2025-01-08 10:49:21 -08:00
plastered_crab d50eb52172 Merge branch 'refs/heads/main' into 1.21.1-TMs 2025-01-07 19:49:30 -08:00
Plastered_Crab 5e5cadd314 Some more changes to unported files 2024-12-26 16:34:29 -08:00
Plastered_Crab 75b06f82f0 Oops forgor two files (they were not staged oops again) 2024-12-26 16:21:04 -08:00
Plastered_Crab 2ab050aa60 Oops forgor two files 2024-12-26 16:20:25 -08:00
Plastered_Crab 6d2f645e4a More work to port over TM stuff to 1.21.1 2024-12-26 16:10:04 -08:00
Plastered_Crab 9f937e29f2 Merge branch 'main' into 1.21.1-TMs 2024-12-26 13:54:27 -08:00
Plastered_Crab abc61a96c8 Merge branch 'main' into 1.21.1-TMs 2024-12-17 10:21:05 -08:00
Plastered_Crab b1d10822d4 Merge branch 'main' into 1.21.1-TMs 2024-12-12 08:35:22 -08:00
Plastered_Crab 09d984456d Start of new branch for 1.21.1 version of TM Machine code (this was painful) 2024-11-26 15:04:32 -08:00
6217 changed files with 92387 additions and 34057 deletions
+1
View File
@@ -36,6 +36,7 @@ common/src/main/resources/assets/cobblemon/showdown
# Generated files
*/generated/resources/*
/fabric/src/generated/resources/cobblemon-common.accesswidener
/fabric/src/main/generated/*
/.ignored/
common/.fabric
.kotlin/
+5 -9
View File
@@ -1,4 +1,4 @@
image: amazoncorretto:25
image: amazoncorretto:21
before_script:
- export GRADLE_USER_HOME=`pwd`/.gradle
@@ -16,7 +16,6 @@ check_assets_cache:
stage: preprocessing
script:
- echo "Checking if cached hash matches current hash"
- yum install -y findutils
# Calculate the current hash
- find common/src/main/resources/assets common/src/main/resources/data -type f -exec sha256sum {} + | sort -k 2 | sha256sum > current_hash.txt
@@ -72,8 +71,8 @@ setup_packsquash:
- echo "Installing wget & unzip"
- yum install -y wget unzip
- echo "Downloading PackSquash"
- wget https://github.com/ComunidadAylas/PackSquash/releases/download/v0.4.1/packsquash-x86_64-unknown-linux-musl.zip
- unzip packsquash-x86_64-unknown-linux-musl.zip -d ./packsquash_bin
- wget https://github.com/ComunidadAylas/PackSquash/releases/download/v0.4.0/PackSquash.CLI.executable.x86_64-unknown-linux-musl.zip
- unzip PackSquash.CLI.executable.x86_64-unknown-linux-musl.zip -d ./packsquash_bin
- echo "Creating PackSquash options.toml"
- |
cat <<EOF > ./options.toml
@@ -149,7 +148,6 @@ build:
dependencies:
- replace_resources
script:
- yum install -y findutils
- export GRADLE_OPTS="-Xmx4G -Xms4G"
- chmod +x ./gradlew
- ./gradlew build
@@ -165,7 +163,6 @@ publish:
rules:
- if: '$CI_PROJECT_PATH == "cable-mc/cobblemon" && $CI_COMMIT_BRANCH == "main"'
script:
- yum install -y findutils
- export GRADLE_OPTS="-Xmx4G -Xms4G"
- chmod +x ./gradlew
- ./gradlew publish
@@ -179,10 +176,9 @@ deploy_artifacts:
dependencies:
- build
script:
- yum install -y findutils
- echo "Collecting artifacts..."
- find neoforge/build/libs/ -type f -name "*.jar" | grep -vE "dev-slim|sources|javadoc" | xargs -I {} mv {} ./
- find fabric/build/libs/ -type f -name "*.jar" | grep -vE "dev-slim|sources|javadoc" | xargs -I {} mv {} ./
- find neoforge/build/libs/ -type f -name "*.jar" | grep -vE "dev-shadow|sources|javadoc" | xargs -I {} mv {} ./
- find fabric/build/libs/ -type f -name "*.jar" | grep -vE "dev-shadow|sources|javadoc" | xargs -I {} mv {} ./
- for f in *.jar; do mv "$f" "$(echo "$f" | sed s/+/b$CI_PIPELINE_IID+/)"; done
artifacts:
paths:
+31
View File
@@ -0,0 +1,31 @@
# Changelog
## [1.8.0 (MONTH Xth, 2026)](#1-8-0)
### Additions
- Added a new `cobblemon:structure`, which is a feature without any restrictions allowing the Builders to place certain structures in much more specific manner.
- Added Configs for Infinite Use TMs and Unlocking all TMs
- Added Type Gem blocks
- Added Type Gem Clusters
- Added TMs
- Added TM Machine
- Added Deepslate Core Block
- Added /givetm Command
- Added Move Dex to Pokedex
- Added Disk Rack for storing disks and being an audio sequencer for Noteblocks
### Changes
- Data Monitor can accept Disks (TMs, Music Disks, Upgrade, Dubious Disk, etc) to change look
### Fixes
- Fixed rare Pokémon being far too likely to spawn multiple times in a single spawn cycle. The dev told me that the exact bug is too complicated to explain.
### Developer
- Tweaked the spawning selector interface to take a bucket function rather than a bucket directly.
### Molang & Datapacks
### Particles
### Localization
- Updated translations for:
+16
View File
@@ -0,0 +1,16 @@
### Additions
### Changes
- Wild Pokémon now reliably have at least one offensive move, if they can have offensive moves at that level.
### Fixes
### Developer
### Molang & Datapacks
- Added `moveset_builders` datapack folder for different styles of movesets.
- Added `party_pools` datapack folder for defining groups of Pokémon for the purposes of complex NPC party definitions.
- Added `party_compositions` datapack folder for arranging parties on NPCs that rely on party pools.
- Added `composed_pool` NPC party provider type which combines a party pool with a party composition to create more complex NPC parties.
### Particles
-13
View File
@@ -2,7 +2,6 @@
## [1.7.4 (MONTH Xth, 2026)](#1-7-4)
### Additions
- Added config options to award experience to fainted Pokémon for opponents they helped defeat (`awardExperienceToFaintedPokemon`) and to still award experience for defeated enemies even after battle loss/forfeit (`awardExperienceOnBattleLoss`)
- Party Overlay Exp Gained Animation will now display the amount of EXP the Pokémon gained
- Added a toast to notify players of how they can scroll through their party. Did you know you can hold R and scroll instead of using arrow keys??!
- Added new layer property that makes a layer scroll in a direction. "scrolling": {"speedU": 0.1, "speedV": 0.1}
@@ -22,7 +21,6 @@
- Factor in the weight of pokemon when calculating pushing forces between hitboxes.
- Remade the Starter Selection Screen with new assets
- Refactored berry trees to be less impactful on TPS (more performant)
- Changed the bait effects of the following items: (Vanilla) Sweet & Glow Berries, Golden & Enchanted Golden Apples (Cobblemon) Custap, Eggant, Hopo & Micle Berries, Sweet Hearts
### Fixes
- Fixes https://gitlab.com/cable-mc/cobblemon/-/issues/1943
@@ -40,27 +38,16 @@
- Fixed NeoForge brewing stand unexpectedly crashing users when shift clicking items within it's menu
- Fixed NPCs switching pokemon very often during battles
- Fixed Campfire pot causing crashes under certain circumstances
- Fixed Type Gems not being consumed upon use
- Fixed Ancient Pokeball's to their respective modifiers
- Fixed a Server warning when recalling Pokemon
- Fixed sliding particles incorrectly handling block collision
- Fixed Full Heal not curing status conditions in battle
- Fixed a rare issue with battles locking up when you are forced to switch, with the switch menu appearing instantly.
### Developer
- Added `PokeSnackSpawnerFactory` which allows influence registration on PokeSnack encounters
- Added `FishingSpawnerFactory` which allows influence registration on fishing encounters
- Added `BattleFleeAttemptEvent` fired from `PokemonBattle.checkFleeAttempt`, allowing developers to intercept and control flee attempts
### Molang & Datapacks
- Added basic chatter NPC Behaviour
- q.item.is_enchanted()
- q.item.has_enchantment(minecraft:sharpness, 3)
- Added `has_chosen_starter` & `get_starter_uuid` as available Molang functions
- Added `marks`, `has_mark`, & `remove_marks` as available Molang functions for pokemon
- Added Data Component support for species drops, eg `"components": {"minecraft:custom_model_data": 123}`
- Added new sortOrder field to mark entries, (defaults to 0 if not specified) which controls the order in which marks are rendered on the HUD, with higher numbers being rendered on top of lower numbers
- Added optional `order` field to starter categories. It will allow to explicitly sort categories in starter selection screen
### Localization
- Updated translations for:
+9
View File
@@ -0,0 +1,9 @@
- Nodemaker bug, it thinks jumps are possible from water up an entire block - they aint
https://gyazo.com/759b8285e7c07046ff2e54adf0d7a7ac
- Why is magikarp trying to path through ice
https://gyazo.com/ae230758c529f885eeb0dd91e60530d2
- We should use mixins to put the path node filtering from OmniPathNodeMaker in the base classes otherwise
NPC wandering will be jank too.
+13 -23
View File
@@ -18,10 +18,15 @@ import java.time.format.DateTimeFormatter
plugins {
id("cobblemon.base-conventions")
id("cobblemon.publish-conventions")
id("net.kyori.blossom")
id("org.jetbrains.gradle.plugin.idea-ext")
}
architectury {
common("neoforge", "fabric")
}
repositories {
maven(url = "${rootProject.projectDir}/deps")
maven(url = "https://api.modrinth.com/maven")
@@ -30,38 +35,33 @@ repositories {
mavenLocal()
}
val mappingsAttribute = Attribute.of("net.minecraft.mappings", String::class.java)
dependencies {
implementation(libs.bundles.kotlin)
compileOnly(libs.bundles.common.mixin.compileOnly)
annotationProcessor(libs.mixinExtras.common)
api(libs.molang)
modImplementation(libs.fabric.loader)
modApi(libs.molang)
// Integrations
compileOnlyApi(libs.jei.api)
compileOnly(libs.bundles.common.integrations.compileOnly) {
modCompileOnly(libs.bundles.common.integrations.compileOnly) {
isTransitive = false
}
// LambDynamicLights is handled differently because we need the Mojang-mappings version of it.
compileOnly(libs.lambDynamicLights) {
attributes {
attribute(mappingsAttribute, "mojmap")
modCompileOnly(libs.lambDynamicLights) {
capabilities {
requireCapability("dev.lambdaurora.lambdynamiclights:api-mojmap")
}
}
// Flywheel has no common dep so just pick one and don't use any platform specific code in common
// modCompileOnly(libs.flywheelFabric)
// Showdown
compileOnly(libs.graal.core)
compileOnly(libs.graal.polyglot)
modCompileOnly(libs.graal)
// Data Storage
compileOnly(libs.bundles.mongo)
modCompileOnly(libs.bundles.mongo)
// Unit Testing
testImplementation(libs.bundles.unitTesting)
testRuntimeOnly(libs.junit.platform)
}
tasks.withType<Test> {
@@ -72,16 +72,6 @@ tasks.withType<Test> {
}
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
compilerOptions {
freeCompilerArgs.addAll(
"-Xno-param-assertions",
"-Xno-call-assertions",
"-Xno-receiver-assertions"
)
}
}
sourceSets {
main {
blossom {
+1 -2
View File
@@ -1,2 +1 @@
maven.artifactId = mod
fabric.loom.disableObfuscation=true
maven.artifactId = mod
@@ -36,7 +36,7 @@ public interface Bone {
/**
* Renders a particular bone in relation to a particular entity.
*
* @param context The extractRenderState context this bone is being drawn for.
* @param context The render context this bone is being drawn for.
* @param stack The current [MatrixStack] for the renderer
* @param buffer The vertex consumer deployed by the renderer
* @param packedLight The light level to be applied to the bone
@@ -9,21 +9,20 @@
package com.cobblemon.mod.common.compat.lambdynamiclights;
import com.cobblemon.mod.common.Cobblemon;
import com.cobblemon.mod.common.CobblemonEntities;
import dev.lambdaurora.lambdynlights.api.DynamicLightsContext;
import dev.lambdaurora.lambdynlights.api.DynamicLightsInitializer;
import dev.lambdaurora.lambdynlights.api.entity.luminance.EntityLuminance;
import dev.lambdaurora.lambdynlights.api.item.ItemLightSourceManager;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EntityType;
public class LambDynamicLightsInitializer implements DynamicLightsInitializer {
public static final EntityLuminance.Type POKEMON_LUMINANCE = EntityLuminance.Type.registerSimple(
Identifier.fromNamespaceAndPath(Cobblemon.MODID, "pokemon"),
ResourceLocation.fromNamespaceAndPath(Cobblemon.MODID, "pokemon"),
PokemonLuminance.INSTANCE
);
public static final EntityLuminance.Type PLAYER_LUMINANCE = EntityLuminance.Type.registerSimple(
Identifier.fromNamespaceAndPath(Cobblemon.MODID, "shoulder"),
ResourceLocation.fromNamespaceAndPath(Cobblemon.MODID, "shoulder"),
PlayerLuminance.INSTANCE
);
@@ -33,8 +32,11 @@ public class LambDynamicLightsInitializer implements DynamicLightsInitializer {
context.entityLightSourceManager().onRegisterEvent().register(ctx -> {
ctx.register(EntityType.PLAYER, PlayerLuminance.INSTANCE);
ctx.register(CobblemonEntities.POKEMON, PokemonLuminance.INSTANCE);
});
}
@SuppressWarnings({"removal", "UnstableApiUsage"})
@Override
public void onInitializeDynamicLights(ItemLightSourceManager itemLightSourceManager) {}
}
@@ -10,11 +10,10 @@ package com.cobblemon.mod.common.compat.lambdynamiclights;
import com.cobblemon.mod.common.Cobblemon;
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer;
import com.cobblemon.mod.common.duck.PlayerDuck;
import dev.lambdaurora.lambdynlights.api.entity.luminance.EntityLuminance;
import dev.lambdaurora.lambdynlights.api.item.ItemLightSourceManager;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
@@ -26,7 +25,7 @@ import org.jetbrains.annotations.Range;
public final class PlayerLuminance extends CustomLuminance implements EntityLuminance {
public static final PlayerLuminance INSTANCE = new PlayerLuminance();
private static final TagKey<Item> POKEDEX = TagKey.create(Registries.ITEM, Identifier.fromNamespaceAndPath(Cobblemon.MODID, "pokedex"));
private static final TagKey<Item> POKEDEX = TagKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath(Cobblemon.MODID, "pokedex"));
@Override
public @NotNull Type type() {
@@ -47,8 +46,8 @@ public final class PlayerLuminance extends CustomLuminance implements EntityLumi
}
private @Range(from = 0L, to = 15L) static int shoulderLuminance(@NotNull ItemLightSourceManager itemLightSourceManager, @NotNull Player player) {
final var leftShoulder = PokemonOnShoulderRenderer.shoulderDataFrom(((PlayerDuck)player).getShoulderEntityLeft());
final var rightShoulder = PokemonOnShoulderRenderer.shoulderDataFrom(((PlayerDuck)player).getShoulderEntityRight());
final var leftShoulder = PokemonOnShoulderRenderer.shoulderDataFrom(player.getShoulderEntityLeft());
final var rightShoulder = PokemonOnShoulderRenderer.shoulderDataFrom(player.getShoulderEntityRight());
if (leftShoulder == null && rightShoulder == null) {
return 0;
@@ -1,21 +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.duck;
import net.minecraft.client.player.AbstractClientPlayer;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import org.jetbrains.annotations.Nullable;
public interface AvatarRenderStateDuck {
@Nullable AbstractClientPlayer cobblemon$getMountedPlayer();
void cobblemon$setMountedPlayer(@Nullable AbstractClientPlayer player);
@Nullable PokemonEntity cobblemon$getMountedPokemon();
void cobblemon$setMountedPokemon(@Nullable PokemonEntity pokemonEntity);
}
@@ -30,6 +30,4 @@ public interface CameraDuck {
float cobblemon$getYRot();
void cobblemon$setYRot(float yRot);
void cobblemon$markDirty();
}
@@ -1,30 +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.duck;
import com.cobblemon.mod.common.entity.PoseType;
import net.minecraft.world.entity.LivingEntity;
import org.jetbrains.annotations.Nullable;
public interface LivingEntityRenderStateDuck {
@Nullable LivingEntity cobblemon$getMountedEntity();
void cobblemon$setMountedEntity(@Nullable LivingEntity entity);
float cobblemon$getMountedPartialTick();
void cobblemon$setMountedPartialTick(float partialTick);
int cobblemon$getMountedSeatIndex();
void cobblemon$setMountedSeatIndex(int seatIndex);
@Nullable String cobblemon$getMountedSeatLocator();
void cobblemon$setMountedSeatLocator(@Nullable String seatLocator);
@Nullable PoseType cobblemon$getMountedPoseType();
void cobblemon$setMountedPoseType(@Nullable PoseType poseType);
}
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common.duck;
import net.minecraft.nbt.CompoundTag;
import org.joml.Vector3f;
public interface PlayerDuck {
@@ -16,8 +15,4 @@ public interface PlayerDuck {
Vector3f getDriverInput();
void setLastSentDriverInput(Vector3f driverInput);
Vector3f getLastSentDriverInput();
CompoundTag getShoulderEntityLeft();
CompoundTag getShoulderEntityRight();
void setShoulderEntityLeft(CompoundTag entityNbt);
void setShoulderEntityRight(CompoundTag entityNbt);
}
@@ -8,8 +8,8 @@
package com.cobblemon.mod.common.duck;
import net.minecraft.world.item.crafting.RecipeAccess;
import net.minecraft.world.item.crafting.RecipeManager;
public interface RecipeAwareSlot {
void setRecipeManager(RecipeAccess recipeManager);
void setRecipeManager(RecipeManager recipeManager);
}
@@ -10,12 +10,12 @@ package com.cobblemon.mod.common.duck;
import org.jetbrains.annotations.Nullable;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.SoundSource;
public interface SoundEngineDuck {
void pauseSounds(@Nullable Identifier id, @Nullable SoundSource category);
void pauseSounds(@Nullable ResourceLocation id, @Nullable SoundSource category);
void resumeSounds(@Nullable Identifier id, @Nullable SoundSource category);
void resumeSounds(@Nullable ResourceLocation id, @Nullable SoundSource category);
}
@@ -8,13 +8,13 @@
package com.cobblemon.mod.common.duck;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.SoundSource;
import org.jetbrains.annotations.Nullable;
public interface SoundManagerDuck {
void pauseSounds(@Nullable Identifier id, @Nullable SoundSource category);
void pauseSounds(@Nullable ResourceLocation id, @Nullable SoundSource category);
void resumeSounds(@Nullable Identifier id, @Nullable SoundSource category);
void resumeSounds(@Nullable ResourceLocation id, @Nullable SoundSource category);
}
@@ -13,7 +13,7 @@ import com.cobblemon.mod.common.duck.RidePassenger;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.projectile.arrow.AbstractArrow;
import net.minecraft.world.entity.projectile.AbstractArrow;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.Nullable;
@@ -22,13 +22,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(targets = "net.minecraft.world.entity.animal.bee.Bee$BeeGrowCropGoal")
@Mixin(targets = "net.minecraft.world.entity.animal.Bee$BeeGrowCropGoal")
public abstract class BeeEntityMixin {
@Unique
private BlockState cobblemon$result = null;
@Inject(method = "tick", at = @At(
@Inject(method = "tick()V", at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/block/BonemealableBlock;performBonemeal(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/util/RandomSource;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;)V",
shift = At.Shift.BY,
@@ -14,26 +14,19 @@ import com.cobblemon.mod.common.api.ai.config.task.PathToBeeHiveTaskConfig;
import com.cobblemon.mod.common.api.pokemon.PokemonProperties;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.world.feature.SaccharineTreeFeature;
import com.mojang.logging.LogUtils;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntitySpawnReason;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.ai.memory.MemoryStatus;
import net.minecraft.world.item.component.CustomData;
import net.minecraft.world.item.component.TypedEntityData;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BeehiveBlock;
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
import net.minecraft.world.level.storage.TagValueOutput;
import net.minecraft.world.phys.Vec3;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@@ -45,28 +38,25 @@ import java.util.Objects;
@Mixin(BeehiveBlockEntity.Occupant.class)
public abstract class BeeOccupantMixin {
@Unique
private static final Logger LOGGER = LogUtils.getLogger();
@Inject(method = "createEntity", at = @At("RETURN"), cancellable = true)
private void cobblemon$createEntity(Level level, BlockPos pos, CallbackInfoReturnable<Entity> cir) {
// Needing to replicate all the post op stuff on the hive isn't great
if (cir.getReturnValue() == null) {
final BeehiveBlockEntity.Occupant occupant = (BeehiveBlockEntity.Occupant) (Object) this;
CompoundTag compoundTag = occupant.entityData().copyTagWithoutId();
String id = compoundTag.getStringOr("id", "");
CompoundTag compoundTag = occupant.entityData().copyTag();
String id = compoundTag.getString("id");
Entity entity = null;
if (id.equals(SaccharineTreeFeature.Companion.getPOKEMON_PLACEHOLD_ID())) {
// Special case for Pokemon stuffed into a beenest upon world gen.
// For technical reasons we cannot create them as full entities during world gen.
// So we look for this special id tag and complete the entity when it attempts to exit a hive.
if (compoundTag.contains("pokemonProperties")) {
String properties = compoundTag.getString("pokemonProperties").get();
String properties = compoundTag.getString("pokemonProperties");
PokemonProperties pokemon = PokemonProperties.Companion.parse(properties);
entity = pokemon.createEntity(level);
}
} else {
entity = EntityType.loadEntityRecursive(compoundTag, level, EntitySpawnReason.LOAD, (entityx) -> entityx);
entity = EntityType.loadEntityRecursive(compoundTag, level, (entityx) -> entityx);
}
if (entity instanceof PokemonEntity pokemonEntity) {
@@ -86,11 +76,11 @@ public abstract class BeeOccupantMixin {
// Block has likely been destroyed
var center = pos.getCenter();
newPos = new Vec3(
center.x + level.getRandom().nextFloat() * 0.6 - 0.3,
center.y + level.getRandom().nextFloat() * 0.6 - 0.3,
center.z + level.getRandom().nextFloat() * 0.6 - 0.3
center.x + level.random.nextFloat() * 0.6 - 0.3,
center.y + level.random.nextFloat() * 0.6 - 0.3,
center.z + level.random.nextFloat() * 0.6 - 0.3
);
newYaw = level.getRandom().nextFloat() * 360F;
newYaw = level.random.nextFloat() * 360F;
if (brain.checkMemory(CobblemonMemories.HIVE_LOCATION, MemoryStatus.REGISTERED)) {
brain.eraseMemory(CobblemonMemories.HIVE_LOCATION);
}
@@ -110,7 +100,7 @@ public abstract class BeeOccupantMixin {
if (state.is(BlockTags.BEEHIVES, (blockStateBase) -> blockStateBase.hasProperty(BeehiveBlock.HONEY_LEVEL))) {
int i = state.getValue(BeehiveBlock.HONEY_LEVEL);
if (i < 5) {
int j = level.getRandom().nextInt(100) == 0 ? 2 : 1;
int j = level.random.nextInt(100) == 0 ? 2 : 1;
if (i + j > 5) {
--j;
}
@@ -127,19 +117,16 @@ public abstract class BeeOccupantMixin {
@Inject(method = "of", at = @At("HEAD"), cancellable = true)
private static void cobblemon$of(Entity entity, CallbackInfoReturnable<BeehiveBlockEntity.Occupant> cir) {
if (entity instanceof PokemonEntity pokemonEntity) {
try (ProblemReporter.ScopedCollector reporter = new ProblemReporter.ScopedCollector(pokemonEntity.problemPath(), LOGGER)) {
List<String> IGNORED_BEE_TAGS = BeehiveBlockEntity.IGNORED_BEE_TAGS;
TagValueOutput output = TagValueOutput.createWithContext(reporter, pokemonEntity.registryAccess());
pokemonEntity.save(output);
Objects.requireNonNull(output);
IGNORED_BEE_TAGS.forEach(output::discard);
CompoundTag entityTag = output.buildResult();
boolean hasNectar = pokemonEntity.getBrain().checkMemory(CobblemonMemories.HAS_NECTAR, MemoryStatus.REGISTERED)
&& pokemonEntity.getBrain().getMemory(CobblemonMemories.HAS_NECTAR).orElse(false);
cir.setReturnValue(new BeehiveBlockEntity.Occupant(TypedEntityData.of(pokemonEntity.getType(), entityTag), 0, hasNectar ? 2400 : 600));
cir.cancel();
}
List<String> IGNORED_BEE_TAGS = Arrays.asList("Air", "ArmorDropChances", "ArmorItems", "CanPickUpLoot", "DeathTime", "FallDistance", "FallFlying", "Fire", "HandDropChances", "HandItems", "HurtByTimestamp", "HurtTime", "LeftHanded", "Motion", "NoGravity", "OnGround", "PortalCooldown", "Pos", "Rotation", "Passengers", "leash", "UUID");
CompoundTag compoundTag = new CompoundTag();
entity.save(compoundTag);
Objects.requireNonNull(compoundTag);
IGNORED_BEE_TAGS.forEach(compoundTag::remove);
boolean hasNectar = pokemonEntity.getBrain().checkMemory(CobblemonMemories.HAS_NECTAR, MemoryStatus.REGISTERED)
&& pokemonEntity.getBrain().getMemory(CobblemonMemories.HAS_NECTAR).orElse(false);
cir.setReturnValue(new BeehiveBlockEntity.Occupant(CustomData.of(compoundTag), 0, hasNectar ? 2400 : 600));
cir.cancel();
}
}
}
}
@@ -12,6 +12,7 @@ package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.mixin.accessor.BeeDataAccessor;
import com.cobblemon.mod.common.mixin.accessor.BeehiveBlockEntityAccessor;
import com.cobblemon.mod.common.mixin.accessor.BlockEntityAccessor;
import com.google.common.collect.Lists;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity;
@@ -58,8 +59,8 @@ public abstract class BeehiveBlockEntityMixin {
}
if (isPokemon) {
return BeehiveBlockEntityAccessor.releaseOccupant(
blockEntity.getLevel(),
blockEntity.getBlockPos(),
((BlockEntityAccessor) blockEntityAccessor).getLevel(),
((BlockEntityAccessor) blockEntityAccessor).getWorldPosition(),
state,
occupant,
list,
@@ -0,0 +1,35 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRenderer;
import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRendererRegistry;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
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(BlockEntityWithoutLevelRenderer.class)
public class BuiltinModelItemRendererMixin {
@Inject(method = "renderByItem", at = @At("HEAD"), cancellable = true)
private void cobblemon$useDynamicItemRenderer(ItemStack stack, ItemDisplayContext mode, PoseStack matrices, MultiBufferSource vertexConsumers, int light, int overlay, CallbackInfo ci) {
CobblemonBuiltinItemRenderer renderer = CobblemonBuiltinItemRendererRegistry.INSTANCE.rendererOf(stack.getItem());
if (renderer != null) {
renderer.render(stack, mode, matrices, vertexConsumers, light, overlay);
ci.cancel();
}
}
}
@@ -12,14 +12,12 @@ import com.cobblemon.mod.common.duck.ChannelDuck;
import com.mojang.blaze3d.audio.Channel;
import org.lwjgl.openal.AL10;
import org.lwjgl.openal.EXTEfx;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(Channel.class)
public abstract class ChannelMixin implements ChannelDuck {
@Final
@Shadow
private int source;
@@ -0,0 +1,48 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import static com.cobblemon.mod.common.datafixer.CobblemonSchemas.VERSION_KEY;
import com.cobblemon.mod.common.datafixer.CobblemonSchemas;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.mojang.serialization.MapCodec;
import java.util.Optional;
import java.util.function.Supplier;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.IntTag;
import net.minecraft.resources.ResourceKey;
import net.minecraft.util.datafix.DataFixTypes;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.chunk.storage.ChunkStorage;
import net.minecraft.world.level.storage.DimensionDataStorage;
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.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ChunkStorage.class)
public class ChunkStorageMixin {
//Modifies the NBT returned by the vanilla upgradeChunkTag to also incorporate cobblemon fixup stuff
@ModifyExpressionValue(
method = "upgradeChunkTag(Lnet/minecraft/resources/ResourceKey;Ljava/util/function/Supplier;Lnet/minecraft/nbt/CompoundTag;Ljava/util/Optional;)Lnet/minecraft/nbt/CompoundTag;",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/util/datafix/DataFixTypes;updateToCurrentVersion(Lcom/mojang/datafixers/DataFixer;Lnet/minecraft/nbt/CompoundTag;I)Lnet/minecraft/nbt/CompoundTag;"
)
)
public CompoundTag cobblemon$doChunkFix(
CompoundTag vanillaFixed
) {
int curVersion = vanillaFixed.contains(VERSION_KEY) ? vanillaFixed.getInt(VERSION_KEY) : 0;
return DataFixTypes.CHUNK.update(CobblemonSchemas.getDATA_FIXER(), vanillaFixed, curVersion, CobblemonSchemas.DATA_VERSION);
}
}
@@ -46,7 +46,7 @@ public class ClientPacketListenerMixin {
passengers.stream()
.filter(x -> !occupiedSeats.contains(x))
.filter(Objects::nonNull)
.forEach(x -> x.startRiding(pokemon, true, true));
.forEach(x -> x.startRiding(pokemon, true));
ci.cancel();
}
}
@@ -1,24 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.block.dispenser.DispenserBehaviorRegistry;
import net.minecraft.core.dispenser.DispenseItemBehavior;
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(DispenseItemBehavior.class)
public interface DispenseItemBehaviourMixin {
@Inject(method = "bootStrap", at = @At("TAIL"))
private static void addCobblemonDispenserBehaviors(CallbackInfo ci) {
DispenserBehaviorRegistry.INSTANCE.registerDispenserBehaviors();
}
}
@@ -10,7 +10,7 @@ package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.EnderpearlItem;
@@ -28,7 +28,7 @@ import java.util.Comparator;
@Mixin(EnderpearlItem.class)
public abstract class EnderPearlItemMixin {
@Inject(method = "use", at = @At(value = "HEAD"), cancellable = true)
private void cobblemon$use(Level level, Player player, InteractionHand usedHand, CallbackInfoReturnable<InteractionResult> cir) {
private void cobblemon$use(Level level, Player player, InteractionHand usedHand, CallbackInfoReturnable<InteractionResultHolder<ItemStack>> cir) {
double range = player.entityInteractionRange();
Entity closestEntity = level.getEntities(player, AABB.ofSize(player.position(), range, range, range)).stream()
.filter(entity -> isLookingAt(player, entity))
@@ -36,7 +36,7 @@ public abstract class EnderPearlItemMixin {
.orElse(null);
if (closestEntity instanceof PokemonEntity pokemonEntity) {
if (player.isCrouching() && pokemonEntity.isOwnedBy(player)) {
if (player.isCrouching() && pokemonEntity.getOwnerUUID() == player.getUUID()) {
cir.cancel();
}
}
@@ -13,7 +13,7 @@ import com.cobblemon.mod.common.pokemon.ai.EntityBehaviour;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.goal.AvoidEntityGoal;
import net.minecraft.world.entity.animal.fox.Fox;
import net.minecraft.world.entity.animal.Fox;
import net.minecraft.world.entity.monster.Creeper;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Mixin;
@@ -9,11 +9,19 @@
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.client.CobblemonClient;
import net.minecraft.client.player.AbstractClientPlayer;
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState;
import com.cobblemon.mod.common.entity.PosableEntity;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.client.renderer.entity.player.AvatarRenderer;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.client.resources.PlayerSkin;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.world.entity.player.PlayerModelType;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@@ -25,7 +33,7 @@ import java.util.Map;
@Mixin(EntityRenderDispatcher.class)
public class EntityRenderDispatcherMixin {
@Shadow private Map<PlayerModelType, AvatarRenderer<AbstractClientPlayer>> playerRenderers;
@Shadow private Map<PlayerSkin.Model, EntityRenderer<? extends Player>> playerRenderers;
@Inject(
method = "onResourceManagerReload",
@@ -35,4 +43,55 @@ public class EntityRenderDispatcherMixin {
CobblemonClient.INSTANCE.onAddLayer(this.playerRenderers);
}
}
@Inject(
method = "renderHitbox(Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;Lnet/minecraft/world/entity/Entity;FFFF)V",
at = @At(value = "TAIL")
)
private static void renderLocators(
PoseStack poseStack,
VertexConsumer buffer,
Entity entity,
float red,
float green,
float blue,
float alpha,
CallbackInfo ci
) {
if (entity instanceof PosableEntity posableEntity) {
if (posableEntity.getDelegate() instanceof PosableState state) {
state.getLocatorStates().forEach((locator, matrix) -> {
poseStack.pushPose();
Vec3 pos = matrix.getOrigin().subtract(entity.position());
LevelRenderer.renderLineBox(
poseStack,
buffer,
AABB.ofSize(pos, 0.25, 0.25, 0.25),
0F,
1F,
0F,
1F
);
/*if (locator.contains("middle")){
PoseStack.Pose pose = poseStack.last();
Vector3f vec = matrix.getMatrix().getRotation(new AxisAngle4f()).transform(new Vector3f(0, 0, -1));
buffer.addVertex(pose, pos.toVector3f()).setColor(0xffff00ff).setNormal(pose, vec.x, vec.y, vec.z); //Forward, pink
buffer.addVertex(pose, (float)(pos.x() + vec.x), (float)(pos.y() + vec.y), (float)(pos.z() + vec.z)).setColor(0xffff00ff).setNormal(pose, vec.x, vec.y, vec.z);
vec = matrix.getMatrix().getRotation(new AxisAngle4f()).transform(new Vector3f(0, 1, 0));
buffer.addVertex(pose, pos.toVector3f()).setColor(0xffffff00).setNormal(pose, vec.x, vec.y, vec.z); //Up, yellow
buffer.addVertex(pose, (float)(pos.x() + vec.x), (float)(pos.y() + vec.y), (float)(pos.z() + vec.z)).setColor(0xffffff00).setNormal(pose, vec.x, vec.y, vec.z);
vec = matrix.getMatrix().getRotation(new AxisAngle4f()).transform(new Vector3f(-1, 0, 0));
buffer.addVertex(pose, pos.toVector3f()).setColor(0xff00ffff).setNormal(pose, vec.x, vec.y, vec.z); //Left, cyan
buffer.addVertex(pose, (float)(pos.x() + vec.x), (float)(pos.y() + vec.y), (float)(pos.z() + vec.z)).setColor(0xff00ffff).setNormal(pose, vec.x, vec.y, vec.z);
}*/
poseStack.popPose();
});
}
}
}
}
@@ -14,7 +14,7 @@ import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.goal.AvoidEntityGoal;
import net.minecraft.world.entity.monster.skeleton.AbstractSkeleton;
import net.minecraft.world.entity.monster.AbstractSkeleton;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@@ -23,7 +23,7 @@ import org.spongepowered.asm.mixin.injection.At;
public class EntityStorageMixin {
//Modifies the NBT returned by the vanilla upgradeChunkTag to also incorporate cobblemon fixup stuff
@ModifyExpressionValue(
method = "lambda$loadEntities$0",
method = "method_31731(Lnet/minecraft/world/level/ChunkPos;Ljava/util/Optional;)Lnet/minecraft/world/level/entity/ChunkEntities;",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/chunk/storage/SimpleRegionStorage;upgradeChunkTag(Lnet/minecraft/nbt/CompoundTag;I)Lnet/minecraft/nbt/CompoundTag;"
@@ -32,7 +32,7 @@ public class EntityStorageMixin {
public CompoundTag cobblemon$doEntityFix(
CompoundTag vanillaFixed
) {
int curVersion = vanillaFixed.getIntOr(VERSION_KEY, 0);
int curVersion = vanillaFixed.contains(VERSION_KEY) ? vanillaFixed.getInt(VERSION_KEY) : 0;
CompoundTag newTag = DataFixTypes.ENTITY_CHUNK.update(CobblemonSchemas.getDATA_FIXER(), vanillaFixed, curVersion, CobblemonSchemas.DATA_VERSION);
newTag.put(VERSION_KEY, IntTag.valueOf(CobblemonSchemas.DATA_VERSION));
return newTag;
@@ -15,18 +15,17 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.cobblemon.mod.common.villager.VillagerGatherableItems;
import java.util.Objects;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.npc.villager.Villager;
import net.minecraft.world.entity.npc.villager.VillagerProfession;
import net.minecraft.world.entity.npc.Villager;
import net.minecraft.world.entity.npc.VillagerProfession;
import net.minecraft.world.item.ItemStack;
@Mixin(Villager.class)
public abstract class EntityVillagerMixin {
@Inject(method = "wantsToPickUp", at = @At(value = "RETURN"), cancellable = true)
private void cobblemon$canGather(ServerLevel serverLevel, ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
private void cobblemon$canGather(ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
final Villager villager = (Villager) (Object) this;
if (!ci.getReturnValue() && Objects.equals(villager.getVillagerData().profession().value(), VillagerProfession.FARMER) && villager.getInventory().canAddItem(stack)) {
if (ci.getReturnValue() == false && Objects.equals(villager.getVillagerData().getProfession(), VillagerProfession.FARMER) && villager.getInventory().canAddItem(stack)) {
if(VillagerGatherableItems.INSTANCE.getVillagerGatherableItems().contains(stack.getItem()))
ci.setReturnValue(true);
}
@@ -1,45 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.Cobblemon;
import com.cobblemon.mod.common.CobblemonItems;
import com.cobblemon.mod.common.api.events.CobblemonEvents;
import com.cobblemon.mod.common.api.events.item.LeftoversCreatedEvent;
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
import kotlin.Unit;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.component.Consumable;
import net.minecraft.world.level.Level;
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(FoodProperties.class)
public class FoodPropertiesMixin {
@Inject(method = "onConsume", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/food/FoodData;eat(Lnet/minecraft/world/food/FoodProperties;)V"))
public void dropLeftOvers(Level level, LivingEntity user, ItemStack stack, Consumable consumable, CallbackInfo ci) {
if (!level.isClientSide()) {
if (stack.is(CobblemonItemTags.LEAVES_LEFTOVERS) && level.getRandom().nextDouble() < Cobblemon.config.getAppleLeftoversChance()) {
ItemStack leftovers = new ItemStack(CobblemonItems.LEFTOVERS);
CobblemonEvents.LEFTOVERS_CREATED.postThen(
new LeftoversCreatedEvent(user, leftovers),
_ -> Unit.INSTANCE,
leftoversCreatedEvent -> {
user.handleExtraItemsCreatedOnUse(leftoversCreatedEvent.getLeftovers());
return Unit.INSTANCE;
}
);
}
}
}
}
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.item.ItemProperties;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
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.CallbackInfoReturnable;
@Mixin(ItemProperties.class)
public class ItemPropertiesMixin {
// Mixins into the fishing rod's register() lambda expression
// Without this, the fishing rod item model appears cast when using a PokeRod in the other hand
@Inject(method = "method_27883", at = @At(value = "RETURN", ordinal = 1), cancellable = true)
private static void cobblemon$preventRodMixup(ItemStack itemStack, ClientLevel clientLevel, LivingEntity livingEntity, int i, CallbackInfoReturnable<Float> cir) {
if (!(livingEntity instanceof Player) || ((Player) livingEntity).fishing instanceof PokeRodFishingBobberEntity) {
cir.setReturnValue(0.0f);
}
}
}
@@ -16,7 +16,7 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.ItemInteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
@@ -35,8 +35,8 @@ import static net.minecraft.world.level.block.LecternBlock.HAS_BOOK;
@Mixin(LecternBlock.class)
public abstract class LecternBlockMixin {
@Inject(method = "useItemOn", at = @At(value = "HEAD"), cancellable = true)
private void cobblemon$useItemOn(ItemStack itemStack, BlockState blockState, Level world, BlockPos blockPos, Player player, InteractionHand interactionHand, BlockHitResult blockHitResult, CallbackInfoReturnable<InteractionResult> cir) {
if (!world.isClientSide() && itemStack.getItem() instanceof PokedexItem) {
private void cobblemon$useItemOn(ItemStack itemStack, BlockState blockState, Level world, BlockPos blockPos, Player player, InteractionHand interactionHand, BlockHitResult blockHitResult, CallbackInfoReturnable<ItemInteractionResult> cir) {
if (!world.isClientSide && itemStack.getItem() instanceof PokedexItem) {
BlockEntity blockEntity = world.getBlockEntity(blockPos);
if (!blockState.getValue(HAS_BOOK)
&& blockEntity instanceof net.minecraft.world.level.block.entity.LecternBlockEntity
@@ -53,9 +53,9 @@ public abstract class LecternBlockMixin {
if (lecternEntity instanceof LecternBlockEntity) {
((LecternBlockEntity) lecternEntity).setItemStack((pokedexItemStack));
world.playSound(null, blockPos, CobblemonSounds.POKEDEX_CLOSE, SoundSource.BLOCKS, 0.5F, 1.25F);
cir.setReturnValue(InteractionResult.SUCCESS);
cir.setReturnValue(ItemInteractionResult.SUCCESS);
} else {
cir.setReturnValue(itemStack.isEmpty() && interactionHand == InteractionHand.MAIN_HAND ? InteractionResult.PASS : InteractionResult.TRY_WITH_EMPTY_HAND);
cir.setReturnValue(itemStack.isEmpty() && interactionHand == InteractionHand.MAIN_HAND ? ItemInteractionResult.SKIP_DEFAULT_BLOCK_INTERACTION : ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION);
}
}
}
@@ -23,7 +23,7 @@ import java.util.List;
@Mixin(LightningBolt.class)
public abstract class LightningBoltMixin {
@Inject(method = "spawnFire", at = @At(value = "HEAD"), cancellable = true)
@Inject(method = "spawnFire", at = @At(value = "Head"), cancellable = true)
private void cobblemon$spawnFire(int extraIgnitions, CallbackInfo ci) {
// This prevents fire from spawning around Pokemon who otherwise should be immune to lightning and effectively absorb the hit
final LightningBolt lightningBolt = (LightningBolt) (Object) this;
@@ -41,4 +41,4 @@ public abstract class LightningBoltMixin {
ci.cancel();
}
}
}
}
@@ -15,23 +15,18 @@ import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffectRegistry;
import com.cobblemon.mod.common.api.riding.RidingStyle;
import com.cobblemon.mod.common.api.riding.Seat;
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.SubmarineBehaviour;
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate;
import com.cobblemon.mod.common.client.render.MatrixWrapper;
import com.cobblemon.mod.common.duck.RidePassenger;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.minecraft.core.Holder;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.HitResult;
@@ -60,8 +55,8 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
return cobblemon$orientationController;
}
@Inject(method = "removeEffect", at = @At(value = "TAIL"))
private void cobblemon$onEffectRemoved(Holder<MobEffect> effect, CallbackInfoReturnable<Boolean> cir) {
@Inject(method = "onEffectRemoved", at = @At(value = "TAIL"))
private void cobblemon$onEffectRemoved(MobEffectInstance effect, CallbackInfo ci) {
final LivingEntity entity = (LivingEntity) (Object) this;
if (entity instanceof ServerPlayer) {
ShoulderEffectRegistry.INSTANCE.onEffectEnd((ServerPlayer) entity);
@@ -81,40 +76,27 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
Entity vehicle = this.getVehicle();
if (vehicle instanceof PokemonEntity pokemonEntity && pokemonEntity.getDelegate() instanceof PokemonClientDelegate delegate) {
int seatIndex = pokemonEntity.getPassengers().indexOf(this);
if (seatIndex >= 0 && seatIndex < pokemonEntity.getSeats().size()) {
Seat seat = pokemonEntity.getSeats().get(seatIndex);
MatrixWrapper locator = delegate.getLocatorStates().get(seat.getLocator());
if (locator != null) {
Vec3 locatorOffset = new Vec3(locator.getMatrix().getTranslation(new Vector3f()));
Vec3 eyePosition = cobblemon$getEyePosition(partialTicks, pokemonEntity, locatorOffset);
return cobblemon$pickFromEyePosition(hitDistance, partialTicks, hitFluids, eyePosition);
}
}
Seat seat = pokemonEntity.getSeats().get(seatIndex);
MatrixWrapper locator = delegate.getLocatorStates().get(seat.getLocator());
if ((Object) this instanceof RidePassenger ridePassenger) {
Vec3 rideEyePosition = ridePassenger.cobblemon$getRideEyePos();
if (!rideEyePosition.equals(Vec3.ZERO)) {
return cobblemon$pickFromEyePosition(hitDistance, partialTicks, hitFluids, rideEyePosition);
}
}
Vec3 locatorOffset = new Vec3(locator.getMatrix().getTranslation(new Vector3f()));
Vec3 eyePosition = cobblemon$getEyePosition(partialTicks, pokemonEntity, locatorOffset);
Vec3 viewVector = this.getViewVector(partialTicks);
Vec3 viewDistanceVector = eyePosition.add(viewVector.x * hitDistance, viewVector.y * hitDistance, viewVector.z * hitDistance);
return this.level()
.clip(
new ClipContext(
eyePosition, viewDistanceVector, ClipContext.Block.OUTLINE, hitFluids ? net.minecraft.world.level.ClipContext.Fluid.ANY : net.minecraft.world.level.ClipContext.Fluid.NONE, this
)
);
}
return super.pick(hitDistance, partialTicks, hitFluids);
}
@Unique
private @NotNull HitResult cobblemon$pickFromEyePosition(double hitDistance, float partialTicks, boolean hitFluids, Vec3 eyePosition) {
Vec3 viewVector = this.getViewVector(partialTicks);
Vec3 viewDistanceVector = eyePosition.add(viewVector.x * hitDistance, viewVector.y * hitDistance, viewVector.z * hitDistance);
return this.level()
.clip(
new ClipContext(
eyePosition, viewDistanceVector, ClipContext.Block.OUTLINE, hitFluids ? net.minecraft.world.level.ClipContext.Fluid.ANY : net.minecraft.world.level.ClipContext.Fluid.NONE, this
)
);
}
@Unique
private Vec3 cobblemon$getEyePosition(float partialTicks, PokemonEntity pokemonEntity, Vec3 locatorOffset) {
OrientationController controller = this.getOrientationController();
@@ -136,6 +118,20 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
this.cobblemon$orientationController.tick();
}
@Override
public void absMoveTo(double x, double y, double z, float yaw, float pitch) {
if (cobblemon$orientationController.getActive()) {
this.absMoveTo(x, y, z);
this.setYRot(yaw % 360.0f);
this.setXRot(pitch % 360.0f);
this.yRotO = this.getYRot();
this.xRotO = this.getXRot();
} else {
this.absMoveTo(x, y, z);
this.absRotateTo(yaw, pitch);
}
}
@Inject(method = "decreaseAirSupply", at = @At("HEAD"), cancellable = true)
private void cobblemon$conditionalWaterBreathing(
int currentAir,
@@ -163,10 +159,4 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
}
}
@Inject(method = "stopRiding", at = @At("HEAD"))
public void cobblemon$resetOrientationOnDismount(CallbackInfo ci) {
LivingEntity player = (LivingEntity)(Object)this;
if (!(player.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
controllableVehicle.getOrientationController().setActive(false);
}
}
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import net.minecraft.server.ServerInterface;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
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.CallbackInfoReturnable;
@Mixin(ServerLevel.class)
public abstract class MinecraftDedicatedServerMixin implements ServerInterface {
@Inject(method = "shouldDiscardEntity", at = @At(value = "HEAD"), cancellable = true)
public void cobblemon$allowPokemonSpawns(Entity entity, CallbackInfoReturnable<Boolean> callback) {
if (entity instanceof PokemonEntity) {
callback.setReturnValue(false);
}
}
}
@@ -0,0 +1,52 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.block.entity.TMShelfBlockEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.NoteBlock;
import net.minecraft.world.level.block.state.properties.NoteBlockInstrument;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(NoteBlock.class)
public abstract class NoteBlockMixin {
@Inject(method = "triggerEvent", at = @At("HEAD"), cancellable = true)
private void cobblemon$triggerTMShelfSequencer(BlockState state, Level level, BlockPos pos, int type, int data, CallbackInfoReturnable<Boolean> cir) {
final BlockPos shelfPos = pos.below();
final BlockEntity blockEntity = level.getBlockEntity(shelfPos);
if (!(blockEntity instanceof TMShelfBlockEntity tmShelfBlockEntity)) {
return;
}
if (!level.isClientSide) {
final BlockPos instrumentPos = shelfPos.below();
final SoundEvent soundEvent;
if (level.getBlockState(instrumentPos).isAir()) {
soundEvent = SoundEvents.NOTE_BLOCK_BIT.value();
} else {
final NoteBlockInstrument instrument = level.getBlockState(instrumentPos).instrument();
final Holder<SoundEvent> holder = instrument.getSoundEvent();
soundEvent = holder.value();
}
tmShelfBlockEntity.onNoteBlockPulse(level, pos, soundEvent);
}
// Suppress vanilla note-block playback while it is on top of a TM Shelf.
cir.setReturnValue(false);
}
}
@@ -9,8 +9,7 @@
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.api.snowstorm.ParticleMaterials;
import com.cobblemon.mod.common.client.particle.SnowstormParticleGroup;
import java.util.ArrayList;
import com.google.common.collect.ImmutableList;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
@@ -18,10 +17,8 @@ import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List;
import net.minecraft.client.particle.ParticleGroup;
import net.minecraft.client.particle.ParticleEngine;
import net.minecraft.client.particle.ParticleRenderType;
@@ -34,21 +31,7 @@ final class ParticleManagerMixin {
@Inject(at = @At("RETURN"), method = "<clinit>")
private static void lodestone$addTypes(CallbackInfo ci) {
ArrayList<ParticleRenderType> types = new ArrayList<>(RENDER_ORDER);
types.add(ParticleMaterials.INSTANCE.getADD());
types.add(ParticleMaterials.INSTANCE.getALPHA());
types.add(ParticleMaterials.INSTANCE.getBLEND());
types.add(ParticleMaterials.INSTANCE.getOPAQUE());
RENDER_ORDER = types;
RENDER_ORDER = ImmutableList.<ParticleRenderType>builder().addAll(RENDER_ORDER)
.add(ParticleMaterials.INSTANCE.getADD(), ParticleMaterials.INSTANCE.getALPHA(), ParticleMaterials.INSTANCE.getBLEND(), ParticleMaterials.INSTANCE.getOPAQUE()).build();
}
@Inject(method = "createParticleGroup", at = @At("HEAD"), cancellable = true)
private void cobblemon$createSnowstormParticleGroup(ParticleRenderType renderType, CallbackInfoReturnable<ParticleGroup<?>> cir) {
if (renderType == ParticleMaterials.INSTANCE.getADD()
|| renderType == ParticleMaterials.INSTANCE.getALPHA()
|| renderType == ParticleMaterials.INSTANCE.getBLEND()
|| renderType == ParticleMaterials.INSTANCE.getOPAQUE()) {
cir.setReturnValue(new SnowstormParticleGroup((ParticleEngine) (Object) this, renderType));
}
}
}
}
@@ -13,11 +13,12 @@ import com.cobblemon.mod.common.CobblemonItems;
import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.api.events.CobblemonEvents;
import com.cobblemon.mod.common.api.events.item.LeftoversCreatedEvent;
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies;
import com.cobblemon.mod.common.api.orientation.OrientationController;
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies;
import com.cobblemon.mod.common.api.riding.RidingStyle;
import com.cobblemon.mod.common.api.riding.behaviour.types.air.HoverBehaviour;
import com.cobblemon.mod.common.api.storage.party.PartyStore;
import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore;
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
import com.cobblemon.mod.common.duck.PlayerDuck;
import com.cobblemon.mod.common.duck.RidePassenger;
@@ -31,12 +32,13 @@ import com.cobblemon.mod.common.pokemon.Species;
import com.cobblemon.mod.common.util.CompoundTagExtensionsKt;
import com.cobblemon.mod.common.util.CompoundTagUtilities;
import com.cobblemon.mod.common.util.DataKeys;
import com.cobblemon.mod.common.util.ShoulderEntitySynchronizer;
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.damagesource.DamageSource;
@@ -49,12 +51,10 @@ import net.minecraft.world.entity.player.Player;
import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import net.minecraft.resources.Identifier;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
import org.joml.Vector3f;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -66,23 +66,34 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.*;
import java.util.stream.Collectors;
@Mixin(Player.class)
public abstract class PlayerMixin extends LivingEntity implements ScannableEntity, OrientationControllable, PlayerDuck, RidePassenger {
@Unique
private CompoundTag cobblemon$shoulderEntityLeft = new CompoundTag();
@Unique
private CompoundTag cobblemon$shoulderEntityRight = new CompoundTag();
@Unique
private Vector3f cobblemon$driverInput;
@Unique
private Vector3f cobblemon$lastSentDriverInput;
@Shadow public abstract CompoundTag getShoulderEntityLeft();
@Shadow public abstract CompoundTag getShoulderEntityRight();
@Shadow public abstract void respawnEntityOnShoulder(CompoundTag entityNbt);
@Shadow public abstract void setShoulderEntityRight(CompoundTag entityNbt);
@Shadow public abstract void setShoulderEntityLeft(CompoundTag entityNbt);
@Shadow public abstract boolean isSpectator();
@Shadow public abstract boolean addItem(ItemStack stack);
@Shadow public abstract void displayClientMessage(Component message, boolean overlay);
@Shadow @Final private static Map<Pose, EntityDimensions> POSES;
@Shadow @Final public static EntityDimensions STANDING_DIMENSIONS;
@Shadow protected int jumpTriggerTime;
@Unique private final OrientationController cobblemon$orientationController = new OrientationController(this);
@@ -96,70 +107,71 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
super(p_20966_, p_20967_);
}
@Inject(method = "readAdditionalSaveData", at = @At("TAIL"))
private void cobblemon$readShoulderData(ValueInput input, CallbackInfo ci) {
input.read("ShoulderEntityLeft", CompoundTag.CODEC)
.ifPresent(entityNbt -> this.cobblemon$setShoulderEntity(true, entityNbt, false));
input.read("ShoulderEntityRight", CompoundTag.CODEC)
.ifPresent(entityNbt -> this.cobblemon$setShoulderEntity(false, entityNbt, false));
}
@Inject(method = "addAdditionalSaveData", at = @At("TAIL"))
private void cobblemon$writeShoulderData(ValueOutput output, CallbackInfo ci) {
CompoundTag leftShoulder = this.getShoulderEntityLeft();
if (!leftShoulder.isEmpty()) {
output.store("ShoulderEntityLeft", CompoundTag.CODEC, leftShoulder);
}
CompoundTag rightShoulder = this.getShoulderEntityRight();
if (!rightShoulder.isEmpty()) {
output.store("ShoulderEntityRight", CompoundTag.CODEC, rightShoulder);
@Inject(method = "respawnEntityOnShoulder", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/EntityType;create(Lnet/minecraft/nbt/CompoundTag;Lnet/minecraft/world/level/Level;)Ljava/util/Optional;"), cancellable = true)
private void cobblemon$removePokemon(CompoundTag nbt, CallbackInfo ci) {
if (CompoundTagExtensionsKt.isPokemonEntity(nbt)) {
final UUID uuid = CompoundTagUtilities.getPokemonID(nbt);
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityRight())) {
final UUID uuidRight = CompoundTagUtilities.getPokemonID(this.getShoulderEntityRight());
if (uuid.equals(uuidRight)) {
this.recallPokemon(uuidRight);
this.setShoulderEntityRight(new CompoundTag());
}
}
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityLeft())) {
final UUID uuidLeft = CompoundTagUtilities.getPokemonID(this.getShoulderEntityLeft());
if (uuid.equals(uuidLeft)) {
this.recallPokemon(uuidLeft);
this.setShoulderEntityLeft(new CompoundTag());
}
}
ci.cancel();
}
}
@Override
public EntityDimensions getDefaultDimensions(Pose pose) {
if (this.getVehicle() instanceof PokemonEntity) {
return super.getDefaultDimensions(Pose.STANDING);
return STANDING_DIMENSIONS;
}
return super.getDefaultDimensions(pose);
return POSES.getOrDefault(pose, STANDING_DIMENSIONS);
}
@Override
public CompoundTag getShoulderEntityLeft() {
return this.cobblemon$shoulderEntityLeft;
}
@Override
public CompoundTag getShoulderEntityRight() {
return this.cobblemon$shoulderEntityRight;
}
@Override
public void setShoulderEntityLeft(CompoundTag entityNbt) {
this.cobblemon$setShoulderEntity(true, entityNbt, true);
}
@Override
public void setShoulderEntityRight(CompoundTag entityNbt) {
this.cobblemon$setShoulderEntity(false, entityNbt, true);
}
@Unique
private void cobblemon$setShoulderEntity(boolean isLeftShoulder, CompoundTag entityNbt, boolean shouldSync) {
CompoundTag copied = entityNbt == null ? new CompoundTag() : entityNbt.copy();
if (isLeftShoulder) {
this.cobblemon$shoulderEntityLeft = copied;
} else {
this.cobblemon$shoulderEntityRight = copied;
@Inject(
method = "removeEntitiesOnShoulder",
at = @At(
value = "JUMP",
opcode = Opcodes.IFGE,
ordinal = 0,
shift = At.Shift.AFTER
),
cancellable = true
)
private void cobblemon$preventPokemonDropping(CallbackInfo ci) {
// We want to allow both of these to forcefully remove the entities
if (this.isSpectator() || this.isDeadOrDying())
return;
if (!CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityLeft())) {
this.respawnEntityOnShoulder(this.getShoulderEntityLeft());
this.setShoulderEntityLeft(new CompoundTag());
}
if (!CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityRight())) {
this.respawnEntityOnShoulder(this.getShoulderEntityRight());
this.setShoulderEntityRight(new CompoundTag());
}
ci.cancel();
}
if (shouldSync && !this.level().isClientSide() && (Object)this instanceof ServerPlayer player) {
ShoulderEntitySynchronizer.sync(player);
private void recallPokemon(UUID uuid) {
// We need to do this cause the Entity doesn't store a reference to its storage
final PartyStore party = Cobblemon.INSTANCE.getStorage().getParty(this.getUUID(), this.registryAccess());
for (Pokemon pokemon : party) {
if (pokemon.getUuid().equals(uuid)) {
pokemon.recall();
}
}
}
@Redirect(
method = "getDestroySpeed",
at = @At(
@@ -186,11 +198,39 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
return player.onGround();
}
@Inject(
method = "eat",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/player/Player;getFoodData()Lnet/minecraft/world/food/FoodData;",
shift = At.Shift.AFTER
)
)
public void onEatFood(Level world, ItemStack stack, FoodProperties foodComponent, CallbackInfoReturnable<ItemStack> cir) {
if (!level().isClientSide) {
if (stack.is(CobblemonItemTags.LEAVES_LEFTOVERS) && level().random.nextDouble() < Cobblemon.config.getAppleLeftoversChance()) {
ItemStack leftovers = new ItemStack(CobblemonItems.LEFTOVERS);
ServerPlayer player = Objects.requireNonNull(getServer()).getPlayerList().getPlayer(uuid);
assert player != null;
CobblemonEvents.LEFTOVERS_CREATED.postThen(
new LeftoversCreatedEvent(player, leftovers),
leftoversCreatedEvent -> null,
leftoversCreatedEvent -> {
if(!player.addItem(leftoversCreatedEvent.getLeftovers())) {
var itemPos = player.getLookAngle().scale(0.5f).add(position());
level().addFreshEntity(new ItemEntity(level(), itemPos.x(), itemPos.y(), itemPos.z(), leftoversCreatedEvent.getLeftovers()));
}
return null;
}
);
}
}
}
@Inject(method = "isInvulnerableTo", at = @At("HEAD"), cancellable = true)
public void isInvulnerableTo(net.minecraft.server.level.ServerLevel serverLevel, DamageSource source, CallbackInfoReturnable<Boolean> ci) {
if ((Object) this instanceof ServerPlayer player) {
boolean invulnerableInBattle = serverLevel.getGameRules().get(CobblemonGameRules.BATTLE_INVULNERABILITY);
public void isInvulnerableTo(DamageSource source, CallbackInfoReturnable<Boolean> ci) {
if (!level().isClientSide && (Object) this instanceof ServerPlayer player) {
boolean invulnerableInBattle = this.level().getGameRules().getBoolean(CobblemonGameRules.BATTLE_INVULNERABILITY);
boolean inBattle = Cobblemon.INSTANCE.getBattleRegistry().getBattleByParticipatingPlayer(player) != null;
if (invulnerableInBattle && inBattle) {
ci.setReturnValue(true);
@@ -200,40 +240,34 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
@Override @Nullable
public PokedexEntityData resolvePokemonScan() {
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityRight())) {
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityRight())){
return getDataFromShoulderPokemon(this.getShoulderEntityRight());
}
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityLeft())) {
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityLeft())){
return getDataFromShoulderPokemon(this.getShoulderEntityLeft());
}
return null;
}
@Nullable
@Unique
@Nullable @Unique
private PokedexEntityData getDataFromShoulderPokemon(CompoundTag shoulderTag) {
Pokemon pokemon;
if (level().isClientSide()) {
CompoundTag pokemonTag = shoulderTag.getCompound(DataKeys.POKEMON).orElse(new CompoundTag());
if (level().isClientSide) {
CompoundTag pokemonTag = shoulderTag.getCompound(DataKeys.POKEMON);
if (pokemonTag.isEmpty()) return null;
String speciesId = pokemonTag.getString(DataKeys.POKEMON_SPECIES_IDENTIFIER).orElse("");
if (speciesId.isEmpty()) return null;
Species species = PokemonSpecies.getByIdentifier(Identifier.parse(speciesId));
Species species = PokemonSpecies.getByIdentifier(ResourceLocation.parse(pokemonTag.getString(DataKeys.POKEMON_SPECIES_IDENTIFIER)));
if (species == null) return null;
String formId = pokemonTag.getString(DataKeys.POKEMON_FORM_ID).orElse("");
String formId = pokemonTag.getString(DataKeys.POKEMON_FORM_ID);
FormData form = species.getStandardForm();
List<FormData> formList = species.getForms().stream().filter(it -> it.formOnlyShowdownId().equals(formId)).toList();
if (!formList.isEmpty()) form = formList.getFirst();
if (form == null) return null;
String genderString = pokemonTag.getString(DataKeys.POKEMON_GENDER).orElse("");
String genderString = pokemonTag.getString(DataKeys.POKEMON_GENDER);
if (genderString.isEmpty()) return null;
Gender gender = Gender.valueOf(genderString);
boolean shiny = pokemonTag.getBoolean(DataKeys.POKEMON_SHINY).orElse(false);
int level = pokemonTag.getInt(DataKeys.POKEMON_LEVEL).orElse(0);
Set<String> aspects = new HashSet<>();
for (var tag : shoulderTag.getList(DataKeys.SHOULDER_ASPECTS).orElse(new ListTag())) {
tag.asString().ifPresent(aspects::add);
}
boolean shiny = pokemonTag.getBoolean(DataKeys.POKEMON_SHINY);
int level = pokemonTag.getInt(DataKeys.POKEMON_LEVEL);
Set<String> aspects = shoulderTag.getList(DataKeys.SHOULDER_ASPECTS, Tag.TAG_STRING).stream().map(Tag::getAsString).collect(Collectors.toSet());
pokemon = new Pokemon();
pokemon.setSpecies(species);
@@ -243,8 +277,8 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
pokemon.setLevel(level);
pokemon.setForcedAspects(aspects);
} else {
PartyStore party = Cobblemon.INSTANCE.getStorage().getParty(this.getUUID(), this.registryAccess());
pokemon = party.get(CompoundTagExtensionsKt.getUUID(shoulderTag, DataKeys.SHOULDER_UUID));
PlayerPartyStore party = Cobblemon.INSTANCE.getStorage().getParty(this.getUUID(), this.registryAccess());
pokemon = party.get(shoulderTag.getUUID(DataKeys.SHOULDER_UUID));
}
return (pokemon == null) ? null : new PokedexEntityData(pokemon, null);
}
@@ -254,6 +288,21 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
return this;
}
@Override
public void absMoveTo(double x, double y, double z, float yaw, float pitch) {
if (cobblemon$orientationController.getActive()) {
this.absMoveTo(x, y, z);
this.setYRot(yaw % 360.0f);
this.setXRot(pitch % 360.0f);
this.yRotO = this.getYRot();
this.xRotO = this.getXRot();
}
else {
this.absMoveTo(x, y, z);
this.absRotateTo(yaw, pitch);
}
}
@WrapOperation(
method = "rideTick()V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;wantsToStopRiding()Z")
@@ -1,42 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.CobblemonRecipeBookTypes;
import net.minecraft.stats.RecipeBookSettings;
import net.minecraft.world.inventory.RecipeBookType;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.function.UnaryOperator;
@Mixin(RecipeBookSettings.class)
public class RecipeBookSettingsMixin {
@Unique
private RecipeBookSettings.TypeSettings cobblemon$cookingPot = new RecipeBookSettings.TypeSettings(false, false);
@Inject(method = "getSettings", at = @At("HEAD"), cancellable = true)
public void getSettings(RecipeBookType type, CallbackInfoReturnable<RecipeBookSettings.TypeSettings> cir) {
if (type == CobblemonRecipeBookTypes.INSTANCE.getCOOKING_POT()) {
cir.setReturnValue(cobblemon$cookingPot);
}
}
@Inject(method = "updateSettings", at = @At("HEAD"), cancellable = true)
private void updateSetting(RecipeBookType recipeBookType, UnaryOperator<RecipeBookSettings.TypeSettings> operator, CallbackInfo ci) {
if (recipeBookType == CobblemonRecipeBookTypes.INSTANCE.getCOOKING_POT()) {
cobblemon$cookingPot = operator.apply(cobblemon$cookingPot);
ci.cancel();
}
}
}
@@ -1,94 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.CobblemonRecipePropertySets;
import com.cobblemon.mod.common.item.crafting.CookingPotRecipeBase;
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.world.item.crafting.RecipePropertySet;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
@Mixin(RecipeManager.class)
public abstract class RecipeManagerMixin {
@Shadow
@Final
private static Map<ResourceKey<RecipePropertySet>, RecipeManager.IngredientExtractor> RECIPE_PROPERTY_SETS;
@WrapOperation(method = "<clinit>", at = @At(value = "INVOKE", target = "Ljava/util/Map;of(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/util/Map;"))
private static Map poggers(Object k1, Object v1,
Object k2, Object v2,
Object k3, Object v3,
Object k4, Object v4,
Object k5, Object v5,
Object k6, Object v6,
Object k7, Object v7,
Operation<Map> original) {
return new HashMap(original.call(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7));
}
@Inject(method = "<clinit>", at = @At("TAIL"))
private static void cobblemon$addPropertySets(CallbackInfo ci) {
RECIPE_PROPERTY_SETS.put(CobblemonRecipePropertySets.INSTANCE.getBREWING_BOTTLE(), recipe -> {
if (recipe instanceof BrewingStandRecipe brew) {
return Optional.of(brew.getBottle());
}
return Optional.empty();
});
RECIPE_PROPERTY_SETS.put(CobblemonRecipePropertySets.INSTANCE.getBREWING_INPUT(), recipe -> {
if (recipe instanceof BrewingStandRecipe brew) {
return Optional.of(brew.getInput());
}
return Optional.empty();
});
RECIPE_PROPERTY_SETS.put(CobblemonRecipePropertySets.INSTANCE.getCOOKING_POT_FLAVOUR_PROCESSOR(), recipe -> {
if (recipe instanceof CookingPotRecipeBase cooking && cooking.getSeasoningProcessors().stream().anyMatch(x -> x.getType().equals("flavour"))) {
return Optional.of(Ingredient.of(cooking.getResult().item().value()));
}
return Optional.empty();
});
RECIPE_PROPERTY_SETS.put(CobblemonRecipePropertySets.INSTANCE.getCOOKING_POT_FOOD_PROCESSOR(), recipe -> {
if (recipe instanceof CookingPotRecipeBase cooking && cooking.getSeasoningProcessors().stream().anyMatch(x -> x.getType().equals("food"))) {
return Optional.of(Ingredient.of(cooking.getResult().item().value()));
}
return Optional.empty();
});
RECIPE_PROPERTY_SETS.put(CobblemonRecipePropertySets.INSTANCE.getCOOKING_POT_MOB_EFFECTS_PROCESSOR(), recipe -> {
if (recipe instanceof CookingPotRecipeBase cooking && cooking.getSeasoningProcessors().stream().anyMatch(x -> x.getType().equals("mob_effects"))) {
return Optional.of(Ingredient.of(cooking.getResult().item().value()));
}
return Optional.empty();
});
RECIPE_PROPERTY_SETS.put(CobblemonRecipePropertySets.INSTANCE.getCOOKING_POT_SPAWN_BAIT_PROCESSOR(), recipe -> {
if (recipe instanceof CookingPotRecipeBase cooking && cooking.getSeasoningProcessors().stream().anyMatch(x -> x.getType().equals("spawn_bait"))) {
return Optional.of(Ingredient.of(cooking.getResult().item().value()));
}
return Optional.empty();
});
}
}
@@ -19,7 +19,6 @@ import com.cobblemon.mod.common.mixin.accessor.TrackedEntityAccessor;
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateDriverInputPacket;
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateOrientationPacket;
import com.cobblemon.mod.common.net.messages.client.pokemon.update.ClientboundUpdateRidingStatePacket;
import com.mojang.authlib.GameProfile;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minecraft.network.protocol.Packet;
import net.minecraft.server.level.ChunkMap;
@@ -28,8 +27,6 @@ import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerPlayerConnection;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import org.joml.Matrix3f;
import org.joml.Vector3f;
import org.spongepowered.asm.mixin.Final;
@@ -46,6 +43,9 @@ import java.util.function.Consumer;
@Mixin(ServerEntity.class)
public abstract class ServerEntityMixin {
@Shadow
@Final
private Consumer<Packet<?>> broadcast;
@Shadow
@Final
private Entity entity;
@@ -30,14 +30,14 @@ public abstract class ServerLevelMixin {
final ServerLevel serverLevel = (ServerLevel) (Object) this;
if (ci.getReturnValue().isEmpty()) {
// Search for Pokemon with the ability Lightning Rod and redirect to them
AABB aABB = AABB.encapsulatingFullBlocks(blockPos, new BlockPos(blockPos.atY(serverLevel.getMaxY() + 1))).inflate(64.0);
AABB aABB = AABB.encapsulatingFullBlocks(blockPos, new BlockPos(blockPos.atY(serverLevel.getMaxBuildHeight()))).inflate(64.0);
List<LivingEntity> list = serverLevel.getEntitiesOfClass(LivingEntity.class, aABB, (livingEntity) -> livingEntity != null
&& livingEntity.isAlive()
&& livingEntity instanceof PokemonEntity
&& ((PokemonEntity) livingEntity).getBeamMode() == 0
&& ((PokemonEntity) livingEntity).getPokemon().getAbility().getName().equals("lightningrod"));
if (!list.isEmpty()) {
ci.setReturnValue(Optional.of((list.get(serverLevel.getRandom().nextInt(list.size()))).blockPosition()));
ci.setReturnValue(Optional.of((list.get(serverLevel.random.nextInt(list.size()))).blockPosition()));
}
}
}
@@ -16,43 +16,29 @@ import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner;
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory;
import com.cobblemon.mod.common.api.stats.CobblemonStats;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.util.CompoundTagUtilities;
import com.cobblemon.mod.common.util.ShoulderEntitySynchronizer;
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ServerPlayer.class)
public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
@Shadow public abstract CompoundTag getShoulderEntityLeft();
@Shadow public abstract CompoundTag getShoulderEntityRight();
@Shadow public abstract void respawnEntityOnShoulder(CompoundTag entityNbt);
@Shadow public abstract void setShoulderEntityRight(CompoundTag entityNbt);
@Shadow public abstract void setShoulderEntityLeft(CompoundTag entityNbt);
@Shadow
public abstract ServerLevel serverLevel();
@Unique
public PlayerSpawner cobblemon$spawner;
@Shadow
private long timeEntitySatOnShoulder;
@Override
public PlayerSpawner getPlayerSpawner() {
ServerPlayer player = (ServerPlayer)(Object)this;
@@ -69,60 +55,21 @@ public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
@Inject(method = "tick", at = @At("TAIL"))
private void cobblemon$tickSpawner(CallbackInfo ci) {
ServerPlayer player = (ServerPlayer)(Object)this;
if (!Cobblemon.config.getEnableSpawning()) {
return;
} else if (!player.level().getGameRules().get(CobblemonGameRules.DO_POKEMON_SPAWNING)) {
} else if (!serverLevel().getGameRules().getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING)) {
return;
}
getPlayerSpawner().tick();
}
@Inject(method = "removeEntitiesOnShoulder", at = @At("HEAD"), cancellable = true)
private void cobblemon$preventPokemonDropping(CallbackInfo ci) {
ServerPlayer player = (ServerPlayer)(Object)this;
if (player.isSpectator() || player.isDeadOrDying()) {
return;
}
long gameTime = player.level().getGameTime();
if (this.timeEntitySatOnShoulder + 20L >= gameTime) {
return;
}
boolean changed = false;
CompoundTag leftShoulder = player.getShoulderEntityLeft();
if (!leftShoulder.isEmpty() && !CompoundTagUtilities.isShoulderPokemon(leftShoulder)) {
respawnEntityOnShoulder(leftShoulder);
setShoulderEntityLeft(new CompoundTag());
changed = true;
}
CompoundTag rightShoulder = player.getShoulderEntityRight();
if (!rightShoulder.isEmpty() && !CompoundTagUtilities.isShoulderPokemon(rightShoulder)) {
respawnEntityOnShoulder(rightShoulder);
setShoulderEntityRight(new CompoundTag());
changed = true;
}
this.timeEntitySatOnShoulder = gameTime;
if (changed) {
ShoulderEntitySynchronizer.sync(player);
}
ci.cancel();
}
@Inject(method = "rideTick", at = @At("HEAD"))
private void cobblemon$updateOrientationControllerRideTick(CallbackInfo ci) {
ServerPlayer player = (ServerPlayer)(Object)this;
Entity vehicle = player.getVehicle();
if (!(vehicle instanceof OrientationControllable controllableVehicle)) return;
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation(vehicle);
var controller = controllableVehicle.getOrientationController();
controller.setActive(shouldUseCustomOrientation);
if (shouldUseCustomOrientation && controller.getOrientation() == null) {
controller.updateOrientation(matrix -> matrix);
}
controllableVehicle.getOrientationController().setActive(shouldUseCustomOrientation);
}
@Unique
@@ -134,9 +81,16 @@ public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
});
}
@Inject(method = "stopRiding", at = @At("HEAD"))
public void cobblemon$resetOrientationOnDismount(CallbackInfo ci) {
ServerPlayer player = (ServerPlayer)(Object)this;
if (!(player.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
controllableVehicle.getOrientationController().setActive(false);
}
//TODO: Switch to sending out on load instead of preventing saving
@ModifyExpressionValue(method = "saveParentVehicle", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;hasExactlyOnePlayerPassenger()Z"))
private boolean cobblemon$cancelSavingPokemonMounts(boolean original, @Local(name = "rootVehicle") Entity entity) {
@ModifyExpressionValue(method = "addAdditionalSaveData", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;hasExactlyOnePlayerPassenger()Z"))
private boolean cobblemon$cancelSavingPokemonMounts(boolean original, @Local(ordinal=0) Entity entity) {
return original && !(entity instanceof PokemonEntity);
}
@@ -13,7 +13,6 @@ import kotlin.Unit;
import net.minecraft.core.BlockPos;
import net.minecraft.core.dispenser.ShearsDispenseItemBehavior;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@@ -25,10 +24,10 @@ public abstract class ShearsDispenserBehaviorMixin {
// This exists, so we can execute our custom interaction only if no one redirected shears interactions to overwrite the vanilla ones.
@Inject(method = "tryShearBeehive", at = @At("HEAD"), cancellable = true)
private static void cobblemon$tryApricornHarvest(ServerLevel serverLevel, ItemStack itemStack, BlockPos blockPos, CallbackInfoReturnable<Boolean> cir) {
final BlockState state = serverLevel.getBlockState(blockPos);
private static void cobblemon$tryApricornHarvest(ServerLevel world, BlockPos pos, CallbackInfoReturnable<Boolean> cir) {
final BlockState state = world.getBlockState(pos);
if (state.getBlock() instanceof ShearableBlock shearableBlock) {
cir.setReturnValue(shearableBlock.attemptShear(serverLevel, state, blockPos, () -> Unit.INSTANCE));
cir.setReturnValue(shearableBlock.attemptShear(world, state, pos, () -> Unit.INSTANCE));
}
}
@@ -1,45 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import static com.cobblemon.mod.common.datafixer.CobblemonSchemas.VERSION_KEY;
import com.cobblemon.mod.common.datafixer.CobblemonSchemas;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.datafix.DataFixTypes;
import net.minecraft.world.level.chunk.storage.SimpleRegionStorage;
import org.spongepowered.asm.mixin.Debug;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@Mixin(SimpleRegionStorage.class)
public class SimpleRegionStorageMixin {
@Final
@Shadow
private DataFixTypes dataFixType;
//Modifies the NBT returned by the vanilla upgradeChunkTag to also incorporate cobblemon fixup stuff
@ModifyExpressionValue(
method = "upgradeChunkTag(Lnet/minecraft/nbt/CompoundTag;ILnet/minecraft/nbt/CompoundTag;I)Lnet/minecraft/nbt/CompoundTag;",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/util/datafix/DataFixTypes;update(Lcom/mojang/datafixers/DataFixer;Lnet/minecraft/nbt/CompoundTag;II)Lnet/minecraft/nbt/CompoundTag;"
)
)
public CompoundTag cobblemon$doChunkFix(
CompoundTag vanillaFixed
) {
int curVersion = vanillaFixed.getIntOr(VERSION_KEY, 0);
return vanillaFixed; //TODO FIGURE OUT WHAT THE HECK IS GOING ON HERE
//return this.dataFixType.update(CobblemonSchemas.getDATA_FIXER(), vanillaFixed, curVersion, CobblemonSchemas.DATA_VERSION);
}
}
@@ -21,8 +21,9 @@ import net.minecraft.client.resources.sounds.SoundInstance;
import net.minecraft.client.resources.sounds.TickableSoundInstance;
import net.minecraft.client.sounds.ChannelAccess;
import net.minecraft.client.sounds.SoundEngine;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.Mth;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
@@ -32,6 +33,7 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import java.util.Iterator;
@@ -69,45 +71,56 @@ public abstract class SoundEngineMixin implements SoundEngineDuck {
/** Resumes the SoundInstance(s) queried by id and/or category. */
@Override
public void resumeSounds(@Nullable Identifier id, @Nullable SoundSource category) {
public void resumeSounds(@Nullable ResourceLocation id, @Nullable SoundSource category) {
if (category != null) {
this.instanceBySource.get(category).forEach((sound) -> {
if (id == null || sound.getIdentifier().equals(id)) resume(sound);
if (id == null || sound.getLocation().equals(id)) resume(sound);
});
} else if (id == null) {
this.instanceToChannel.keySet().forEach(this::resume);
} else {
this.instanceToChannel.keySet().forEach(sound -> {
if (sound.getIdentifier().equals(id)) resume(sound);
if (sound.getLocation().equals(id)) resume(sound);
});
}
}
/** Pauses the SoundInstances queried by id and/or category. */
@Override
public void pauseSounds(@Nullable Identifier id, @Nullable SoundSource category) {
public void pauseSounds(@Nullable ResourceLocation id, @Nullable SoundSource category) {
if (category != null) {
this.instanceBySource.get(category).forEach((sound) -> {
if (id == null || sound.getIdentifier().equals(id)) pause(sound);
if (id == null || sound.getLocation().equals(id)) pause(sound);
});
} else if (id == null) {
this.instanceToChannel.keySet().forEach(this::pause);
} else {
this.instanceToChannel.keySet().forEach(sound -> {
if (sound.getIdentifier().equals(id)) pause(sound);
if (sound.getLocation().equals(id)) pause(sound);
});
}
}
/** Allows stopping all SoundInstances that belong to a queried category. */
@Inject(method = "stop(Lnet/minecraft/resources/Identifier;Lnet/minecraft/sounds/SoundSource;)V", at = @At("HEAD"), cancellable = true)
public void stopSounds(@Nullable Identifier id, @Nullable SoundSource category, CallbackInfo cb) {
@Inject(method = "stop(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/sounds/SoundSource;)V", at = @At("HEAD"), cancellable = true)
public void stopSounds(@Nullable ResourceLocation id, @Nullable SoundSource category, CallbackInfo cb) {
if (id == null && category != null) {
this.instanceBySource.get(category).forEach(this::stop);
cb.cancel();
}
}
/**
* TM Shelf can intentionally push note-block pitches above vanilla's 2.0f ceiling for octave-up playback.
* Keep vanilla clamping for all other sounds.
*/
@Inject(method = "calculatePitch", at = @At("HEAD"), cancellable = true)
private void cobblemon$allowExtendedNoteblockPitch(SoundInstance sound, CallbackInfoReturnable<Float> cir) {
if (sound.getLocation().getPath().startsWith("block.note_block.")) {
cir.setReturnValue(Mth.clamp(sound.getPitch(), 0.5F, 4.0F));
}
}
/** Different behavior for resuming SoundInstances while a BattleMusicInstance is being played. We do not want to resume filtered sounds. */
@Inject(method = "resume()V", at = @At("HEAD"), cancellable = true)
public void resume(CallbackInfo cb) {
@@ -17,7 +17,7 @@ import net.minecraft.client.resources.sounds.SoundInstance;
import net.minecraft.client.resources.sounds.UnderwaterAmbientSoundInstances;
import net.minecraft.client.sounds.SoundEngine;
import net.minecraft.client.sounds.SoundManager;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.SoundSource;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
@@ -26,7 +26,6 @@ import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(SoundManager.class)
public abstract class SoundManagerMixin implements SoundManagerDuck {
@@ -56,20 +55,20 @@ public abstract class SoundManagerMixin implements SoundManagerDuck {
/** Pauses the queried SoundInstance(s). If id is null, will pause all sounds belonging to the SoundCategory. */
@Override
public void pauseSounds(@Nullable Identifier id, @Nullable SoundSource category) {
public void pauseSounds(@Nullable ResourceLocation id, @Nullable SoundSource category) {
((SoundEngineDuck)soundEngine).pauseSounds(id, category);
}
/** Resumes the queried SoundInstance(s). If id is null, will resume all sounds belonging to the SoundCategory. */
@Override
public void resumeSounds(@Nullable Identifier id, @Nullable SoundSource category) {
public void resumeSounds(@Nullable ResourceLocation id, @Nullable SoundSource category) {
((SoundEngineDuck)soundEngine).resumeSounds(id, category);
}
/** Blocks filtered sounds from being played while a BattleMusicInstance is in progress. */
@Inject(method = "play", at = @At("HEAD"), cancellable = true)
public void playStart(SoundInstance soundInstance, CallbackInfoReturnable<SoundEngine.PlayResult> cir) {
if (filterCondition(soundInstance)) cir.cancel();
@Inject(method = "play(Lnet/minecraft/client/resources/sounds/SoundInstance;)V", at = @At("HEAD"), cancellable = true)
public void playStart(SoundInstance sound, CallbackInfo cb) {
if (filterCondition(sound)) cb.cancel();
}
@Inject(method = "playDelayed(Lnet/minecraft/client/resources/sounds/SoundInstance;I)V", at = @At("HEAD"), cancellable = true)
@@ -78,14 +77,14 @@ public abstract class SoundManagerMixin implements SoundManagerDuck {
}
/** Pauses ambient loops while a BattleMusicInstance is in progress. */
@Inject(method = "play", at = @At("TAIL"))
public void playEnd(SoundInstance soundInstance, CallbackInfoReturnable<SoundEngine.PlayResult> cir) {
if (ambientLoopCondition(soundInstance)) this.pauseSounds(soundInstance.getIdentifier(), SoundSource.AMBIENT);
@Inject(method = "play(Lnet/minecraft/client/resources/sounds/SoundInstance;)V", at = @At("TAIL"))
public void playEnd(SoundInstance sound, CallbackInfo cb) {
if (ambientLoopCondition(sound)) this.pauseSounds(sound.getLocation(), SoundSource.AMBIENT);
}
@Inject(method = "playDelayed(Lnet/minecraft/client/resources/sounds/SoundInstance;I)V", at = @At("TAIL"))
public void playEnd(SoundInstance sound, int delay, CallbackInfo cb) {
if (ambientLoopCondition(sound)) this.pauseSounds(sound.getIdentifier(), SoundSource.AMBIENT);
if (ambientLoopCondition(sound)) this.pauseSounds(sound.getLocation(), SoundSource.AMBIENT);
}
/** Clears tracked sounds on the client when disconnected. */
@@ -12,11 +12,10 @@ import com.cobblemon.mod.common.world.CobblemonStructureIDs;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.core.Holder;
import net.minecraft.core.RegistryAccess;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.Identifier;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.chunk.ChunkGenerator;
@@ -40,7 +39,7 @@ import java.util.function.Predicate;
public abstract class StructureMixin {
// Define a set of structures that should not spawn below Sea Level
@Unique
private static final Set<Identifier> RESTRICTED_STRUCTURES = new HashSet<>(Arrays.asList(
private static final Set<ResourceLocation> RESTRICTED_STRUCTURES = new HashSet<>(Arrays.asList(
CobblemonStructureIDs.STONJOURNER_HENGE,
CobblemonStructureIDs.LUNA_HENGE,
CobblemonStructureIDs.SOL_HENGE
@@ -48,13 +47,13 @@ public abstract class StructureMixin {
@Inject(method = "generate", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/levelgen/structure/StructureStart;isValid()Z"),
cancellable = true)
public void cobblemon$isValid(Holder<Structure> structure, ResourceKey<Level> levelKey, RegistryAccess registryAccess, ChunkGenerator chunkGenerator, BiomeSource biomeSource,
public void cobblemon$isValid(RegistryAccess registryAccess, ChunkGenerator chunkGenerator, BiomeSource biomeSource,
RandomState randomState, StructureTemplateManager structureTemplateManager, long seed,
ChunkPos chunkPos, int references, LevelHeightAccessor heightAccessor,
Predicate<Holder<Biome>> validBiome,
CallbackInfoReturnable<StructureStart> cir,
@Local StructureStart structureStart) {
Identifier structureKey = structure.unwrapKey().map(ResourceKey::identifier).orElse(null);
ResourceLocation structureKey = registryAccess.registryOrThrow(Registries.STRUCTURE).getKey((Structure) (Object) this);
if(!RESTRICTED_STRUCTURES.contains(structureKey)) {
return;
}
@@ -65,4 +64,4 @@ public abstract class StructureMixin {
}
}
}
}
}
@@ -29,4 +29,4 @@ public interface StructurePoolAccessor {
@Accessor("templates")
ObjectArrayList<StructurePoolElement> getElements();
}
}
@@ -11,7 +11,7 @@ package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.world.CobblemonStructureIDs;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.core.Registry;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.chunk.ChunkGenerator;
@@ -38,7 +38,7 @@ public abstract class StructurePoolGeneratorMixin {
Map<String, Integer> generatedStructureGroupCounts;
private static final Map<String, Integer> structureMaxes;
private static final Map<Identifier, Set<String>> structureGroups = new HashMap<>();
private static final Map<ResourceLocation, Set<String>> structureGroups = new HashMap<>();
static {
String pokecenter = "pokecenter";
String berry = "berry_farm";
@@ -73,11 +73,11 @@ public abstract class StructurePoolGeneratorMixin {
structureMaxes = Collections.unmodifiableMap(aMap);
}
public Set<String> getGroups(Identifier structureIdentifier) {
public Set<String> getGroups(ResourceLocation structureIdentifier) {
return structureGroups.getOrDefault(structureIdentifier, Set.of());
}
public boolean hasReachedMaximum(Identifier structureIdentifier) {
public boolean hasReachedMaximum(ResourceLocation structureIdentifier) {
Set<String> groups = getGroups(structureIdentifier);
for (String group : groups) {
int count = generatedStructureGroupCounts.getOrDefault(group, 0);
@@ -89,7 +89,7 @@ public abstract class StructurePoolGeneratorMixin {
return false;
}
public void incrementStructureCount(Identifier structureIdentifier) {
public void incrementStructureCount(ResourceLocation structureIdentifier) {
Set<String> groups = getGroups(structureIdentifier);
for (String group : groups) {
generatedStructureGroupCounts.put(group, generatedStructureGroupCounts.getOrDefault(group, 0) + 1);
@@ -107,7 +107,7 @@ public abstract class StructurePoolGeneratorMixin {
while (iterator.hasNext()) {
StructurePoolElement structure = iterator.next();
Identifier structurePieceLocationKey = getCobblemonOnlyLocation(structure);
ResourceLocation structurePieceLocationKey = getCobblemonOnlyLocation(structure);
if (structurePieceLocationKey == null) {
reducedList.add(structure);
continue;
@@ -134,14 +134,14 @@ public abstract class StructurePoolGeneratorMixin {
CallbackInfo ci,
@Local(ordinal = 1) StructurePoolElement structurePoolElement
) {
Identifier structureLocationKey = getCobblemonOnlyLocation(structurePoolElement);
ResourceLocation structureLocationKey = getCobblemonOnlyLocation(structurePoolElement);
if (structureLocationKey != null) {
incrementStructureCount(structureLocationKey);
}
}
private static Identifier getCobblemonOnlyLocation(StructurePoolElement structurePoolElement) {
Identifier location = getLocationIfAvailable(structurePoolElement);
private static ResourceLocation getCobblemonOnlyLocation(StructurePoolElement structurePoolElement) {
ResourceLocation location = getLocationIfAvailable(structurePoolElement);
if (location == null) return null;
if (!location.getNamespace().equals("cobblemon")) return null;
@@ -149,7 +149,7 @@ public abstract class StructurePoolGeneratorMixin {
return location;
}
private static Identifier getLocationIfAvailable(StructurePoolElement structurePoolElement) {
private static ResourceLocation getLocationIfAvailable(StructurePoolElement structurePoolElement) {
if (structurePoolElement instanceof LegacySinglePoolElement legacySinglePoolElement) {
if (legacySinglePoolElement.template.left().isEmpty()) return null;
@@ -162,4 +162,4 @@ public abstract class StructurePoolGeneratorMixin {
return null;
}
}
}
}
@@ -12,7 +12,6 @@ import com.bedrockk.molang.runtime.value.DoubleValue;
import com.cobblemon.mod.common.entity.MoLangScriptingEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.InsideBlockEffectApplier;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.SweetBerryBushBlock;
import net.minecraft.world.level.block.state.BlockState;
@@ -26,15 +25,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public abstract class SweetBerryBushBlockMixin {
@Inject(method = "entityInside", at = @At(value = "HEAD"), cancellable = true)
private void cobblemon$entityInside(
BlockState state,
Level level,
BlockPos pos,
Entity entity,
InsideBlockEffectApplier effectApplier,
boolean moved,
CallbackInfo callbackInfo
) {
private void cobblemon$entityInside(BlockState state, Level level, BlockPos pos, Entity entity, CallbackInfo callbackInfo) {
if (entity instanceof MoLangScriptingEntity) {
if (((MoLangScriptingEntity) entity).getConfig().getMap().getOrDefault("immune_to_sweet_berry_bush_block", DoubleValue.ZERO).asDouble() == 1.0) {
callbackInfo.cancel();
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.Cobblemon;
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.targeting.TargetingConditions;
@@ -24,11 +23,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
public class TargetingConditionsMixin {
@Inject(method = "test", at = @At("HEAD"), cancellable = true)
public void test(ServerLevel serverLevel, LivingEntity baseEntity, LivingEntity targetEntity, CallbackInfoReturnable<Boolean> cir) {
public void test(@Nullable LivingEntity baseEntity, LivingEntity targetEntity, CallbackInfoReturnable<Boolean> ci) {
if (targetEntity instanceof ServerPlayer player) {
if (serverLevel.getGameRules().get(CobblemonGameRules.MOB_TARGET_IN_BATTLE)) return;
if (player.level().getGameRules().getBoolean(CobblemonGameRules.MOB_TARGET_IN_BATTLE)) return;
boolean targetInBattle = Cobblemon.INSTANCE.getBattleRegistry().getBattleByParticipatingPlayer(player) != null;
if (targetInBattle) cir.setReturnValue(false);
if (targetInBattle) ci.setReturnValue(false);
}
}
}
@@ -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.mixin;
import com.cobblemon.mod.common.Cobblemon;
import com.cobblemon.mod.common.CobblemonVillagerProfessions;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import kotlin.Pair;
import net.minecraft.ChatFormatting;
import net.minecraft.client.model.EntityModel;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
import net.minecraft.client.renderer.entity.layers.RenderLayer;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.monster.ZombieVillager;
import net.minecraft.world.entity.npc.Villager;
import net.minecraft.world.entity.npc.VillagerProfession;
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(RenderLayer.class)
public abstract class VillagerProfessionLayerMixin {
@Inject(method = "renderColoredCutoutModel", at = @At(value = "HEAD"), cancellable = true)
private static <T extends LivingEntity> void cobblemon$renderVillagerProfessionLayer(EntityModel<T> entityModel, ResourceLocation resourceLocation, PoseStack poseStack, MultiBufferSource multiBufferSource, int i, T livingEntity, int j, CallbackInfo ci) {
if (resourceLocation.getNamespace().equals(Cobblemon.MODID)) {
VillagerProfession profession = null;
boolean isZombie = false;
if (livingEntity instanceof Villager) profession = ((Villager) livingEntity).getVillagerData().getProfession();
if (livingEntity instanceof ZombieVillager) {
profession = ((ZombieVillager) livingEntity).getVillagerData().getProfession();
isZombie = true;
}
Pair<String, String[]> override = CobblemonVillagerProfessions.INSTANCE.getNameTagOverride(profession);
if (profession != null && override != null) {
String entityName = ChatFormatting.stripFormatting(livingEntity.getName().getString());
boolean nameMatches = false;
for (String name: override.getSecond())
if (entityName.endsWith(name)) {
nameMatches = true;
break;
}
if (nameMatches && resourceLocation.equals(getProfessionResourceLocation(resourceLocation.getNamespace(), ResourceLocation.parse(profession.name()).getPath(), isZombie))) {
ResourceLocation textureLocation = getProfessionResourceLocation(resourceLocation.getNamespace(), override.getFirst(), isZombie);
VertexConsumer vertexConsumer = multiBufferSource.getBuffer(RenderType.entityCutoutNoCull(textureLocation));
entityModel.renderToBuffer(poseStack, vertexConsumer, i, LivingEntityRenderer.getOverlayCoords(livingEntity, 0.0F), j);
ci.cancel();
}
}
}
}
private static ResourceLocation getProfessionResourceLocation(String namespace, String profession, Boolean isZombie) {
return ResourceLocation.fromNamespaceAndPath(namespace, "textures/entity/" + (isZombie ? "zombie_villager" : "villager") + "/profession/" + profession + ".png");
}
}
@@ -0,0 +1,21 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.accessor;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(BlockEntity.class)
public interface BlockEntityAccessor {
@Accessor("level") Level getLevel();
@Accessor("worldPosition") BlockPos getWorldPosition();
}
@@ -0,0 +1,23 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.accessor;
import net.minecraft.world.entity.vehicle.Boat;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(Boat.class)
public interface BoatEntityAccessor {
@Accessor("lastYd")
void setFallVelocity(double fallVelocity);
@Accessor("status")
Boat.Status getLocation();
}
@@ -17,4 +17,4 @@ import org.spongepowered.asm.mixin.gen.Accessor;
public interface ChunkMapAccessor {
@Accessor("entityMap")
Int2ObjectMap<?> getEntityMap();
}
}
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.accessor;
import net.minecraft.world.item.Item;
import net.minecraft.core.dispenser.DispenseItemBehavior;
import net.minecraft.world.level.block.DispenserBlock;
import java.util.Map;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(DispenserBlock.class)
public interface DispenserBlockAccessor {
@Accessor("DISPENSER_REGISTRY")
static Map<Item, DispenseItemBehavior> getItemBehaviors() {
throw new AssertionError();
}
}
@@ -0,0 +1,19 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.accessor;
import net.minecraft.client.gui.components.AbstractSelectionList;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(AbstractSelectionList.class)
public interface EntryListWidgetAccessor {
@Accessor("renderHeader")
boolean getRenderHeader();
}
@@ -8,7 +8,7 @@
package com.cobblemon.mod.common.mixin.accessor;
import net.minecraft.client.gui.components.CycleButton;
import net.minecraft.client.gui.components.StateSwitchingButton;
import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent;
import net.minecraft.network.chat.Component;
import org.spongepowered.asm.mixin.Mixin;
@@ -18,5 +18,5 @@ import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(RecipeBookComponent.class)
public interface RecipeBookComponentAccessor {
@Accessor("filterButton")
CycleButton<Boolean> getFilterButton();
StateSwitchingButton getFilterButton();
}
@@ -1,24 +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.accessor;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(ServerPlayer.class)
public interface ServerPlayerAccessor {
@Invoker("setShoulderEntityLeft")
public void cobblemon$setShoulderEntityLeft(CompoundTag nbt);
@Invoker("setShoulderEntityRight")
public void cobblemon$setShoulderEntityRight(CompoundTag nbt);
@Invoker("respawnEntityOnShoulder")
public void cobblemon$respawnEntityOnShoulder(CompoundTag nbt);
}
@@ -19,4 +19,7 @@ import java.util.Set;
public interface TrackedEntityAccessor {
@Accessor("seenBy")
Set<ServerPlayerConnection> getSeenBy();
}
@Accessor("serverEntity")
ServerEntity getServerEntity();
}
@@ -20,7 +20,6 @@ import net.minecraft.core.NonNullList;
import net.minecraft.world.Containers;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.ItemStackTemplate;
import net.minecraft.world.item.alchemy.PotionBrewing;
import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.item.crafting.RecipeManager;
@@ -49,17 +48,17 @@ public class BrewingStandBlockEntityMixin {
ItemStack itemStack = slots.get(3);
for(int i = 0; i < 3; ++i) {
if (!slots.get(i).isEmpty()){
slots.set(i, recipe.getResult().create());
slots.set(i, recipe.getResult().copy());
}
}
itemStack.shrink(1);
ItemStackTemplate itemStack2 = itemStack.getItem().getCraftingRemainder();
if (itemStack2 != null) {
if (itemStack.getItem().hasCraftingRemainingItem()) {
ItemStack itemStack2 = new ItemStack(itemStack.getItem().getCraftingRemainingItem());
if (itemStack.isEmpty()) {
itemStack = itemStack2.create();
itemStack = itemStack2;
} else {
Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), itemStack2.create());
Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), itemStack2);
}
}
@@ -91,10 +90,7 @@ public class BrewingStandBlockEntityMixin {
}
BrewingStandInput input = new BrewingStandInput(ingredient, bottles);
if (level.getServer() == null) {
return null;
}
RecipeManager recipeManager = level.getServer().getRecipeManager();
RecipeManager recipeManager = level.getRecipeManager();
Optional<RecipeHolder<BrewingStandRecipe>> recipeHolder =
recipeManager.getRecipeFor(CobblemonRecipeTypes.INSTANCE.getBREWING_STAND(), input, level);
@@ -111,7 +107,7 @@ public class BrewingStandBlockEntityMixin {
if (level != null) {
var rm = level.recipeAccess();
var rm = level.getRecipeManager();
//Input slot
if (slot == 3) {
@@ -132,4 +128,4 @@ public class BrewingStandBlockEntityMixin {
}
}
}
}
}
@@ -29,7 +29,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public abstract class BrewingStandMenuMixin {
@Inject(method = "<init>(ILnet/minecraft/world/entity/player/Inventory;Lnet/minecraft/world/Container;Lnet/minecraft/world/inventory/ContainerData;)V", at = @At("TAIL"))
private void captureLevel(int containerId, Inventory playerInventory, Container brewingStandContainer, ContainerData brewingStandData, CallbackInfo ci) {
var recipeManager = playerInventory.player.level().recipeAccess();
var recipeManager = playerInventory.player.level().getRecipeManager();
for (Slot slot : ((BrewingStandMenu) (Object) this).slots) {
if (slot instanceof RecipeAwareSlot awareSlot) {
awareSlot.setRecipeManager(recipeManager);
@@ -12,7 +12,8 @@ import com.cobblemon.mod.common.duck.RecipeAwareSlot;
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
import net.minecraft.world.inventory.BrewingStandMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeAccess;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
@@ -23,10 +24,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
public class IngredientSlotMixin implements RecipeAwareSlot {
@Unique
private RecipeAccess cobblemon$recipeManager;
private RecipeManager cobblemon$recipeManager;
@Override
public void setRecipeManager(RecipeAccess recipeManager) {
public void setRecipeManager(RecipeManager recipeManager) {
this.cobblemon$recipeManager = recipeManager;
}
@@ -12,7 +12,8 @@ import com.cobblemon.mod.common.duck.RecipeAwareSlot;
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
import net.minecraft.world.inventory.BrewingStandMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeAccess;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
@@ -23,10 +24,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
public class PotionSlotMixin implements RecipeAwareSlot {
@Unique
private RecipeAccess cobblemon$recipeManager;
private RecipeManager cobblemon$recipeManager;
@Override
public void setRecipeManager(RecipeAccess recipeManager) {
public void setRecipeManager(RecipeManager recipeManager) {
this.cobblemon$recipeManager = recipeManager;
}
@@ -21,7 +21,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(AbstractClientPlayer.class)
public class AbstractClientPlayerMixin {
@Inject(
method = "getFieldOfViewModifier",
method = "getFieldOfViewModifier()F",
at = @At(
value = "HEAD"
),
@@ -35,7 +35,8 @@ public class AbstractClientPlayerMixin {
// Only modify fov through riding if the pokedex is not open
AbstractClientPlayer player = (AbstractClientPlayer) (Object) this;
// Only modify fov for the driver and not the passengers
if (player != null && player.isPassenger() && player.getVehicle() instanceof PokemonEntity ride && player.getVehicle().getControllingPassenger() == player) {
if (player != null && player.isPassenger() && player.getVehicle() instanceof PokemonEntity && player.getVehicle().getControllingPassenger() == player) {
PokemonEntity ride = (PokemonEntity) player.getVehicle();
// Return custom fov mult for riding
cir.setReturnValue(ride.rideFovMult());
@@ -0,0 +1,46 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.client.render.player.MountedPlayerRenderer;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.model.AgeableListModel;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.model.Model;
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;
/**
* This mixin adds to the head of the renderToBuffer function and allows us to detect if it is a HumanoidModel and
* is being rendered as part of a player in the world who is riding a PokemonEntity. If so we need to obey any
* root animations that have been applied earlier.
*
* @author Hiroku
* @since May 16, 2025
*/
@Mixin(AgeableListModel.class)
public class AgeableListModelMixin {
@Inject(method = "renderToBuffer", at = @At("HEAD"))
private void cobblemon$renderToBuffer(
PoseStack poseStack,
VertexConsumer vertexConsumer,
int packedLight,
int packedOverlay,
int colour,
CallbackInfo ci
) {
Model model = (Model) (Object) this;
if (model instanceof HumanoidModel<?> && MountedPlayerRenderer.shouldApplyRootAnimation) {
MountedPlayerRenderer.INSTANCE.animateRoot(poseStack);
}
}
}
@@ -1,46 +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.duck.AvatarRenderStateDuck;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.entity.state.AvatarRenderState;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
@Mixin(AvatarRenderState.class)
public class AvatarRenderStateMixin implements AvatarRenderStateDuck {
@Unique
private @Nullable AbstractClientPlayer cobblemon$mountedPlayer;
@Unique
private @Nullable PokemonEntity cobblemon$mountedPokemon;
@Override
public @Nullable AbstractClientPlayer cobblemon$getMountedPlayer() {
return this.cobblemon$mountedPlayer;
}
@Override
public void cobblemon$setMountedPlayer(@Nullable AbstractClientPlayer player) {
this.cobblemon$mountedPlayer = player;
}
@Override
public @Nullable PokemonEntity cobblemon$getMountedPokemon() {
return this.cobblemon$mountedPokemon;
}
@Override
public void cobblemon$setMountedPokemon(@Nullable PokemonEntity pokemonEntity) {
this.cobblemon$mountedPokemon = pokemonEntity;
}
}
@@ -1,55 +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.duck.AvatarRenderStateDuck;
import com.cobblemon.mod.common.duck.LivingEntityRenderStateDuck;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.entity.player.AvatarRenderer;
import net.minecraft.client.renderer.entity.state.AvatarRenderState;
import net.minecraft.world.entity.Avatar;
import net.minecraft.world.phys.Vec3;
import org.objectweb.asm.Opcodes;
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;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(AvatarRenderer.class)
public abstract class AvatarRendererMixin {
@Inject(method = "extractRenderState", at = @At("TAIL"))
private void cobblemon$captureMountedPlayer(Avatar avatar, AvatarRenderState state, float partialTick, CallbackInfo ci) {
AvatarRenderStateDuck duck = (AvatarRenderStateDuck) state;
LivingEntityRenderStateDuck livingDuck = (LivingEntityRenderStateDuck) state;
if (avatar instanceof AbstractClientPlayer player && player.getVehicle() instanceof PokemonEntity pokemonEntity) {
duck.cobblemon$setMountedPlayer(player);
duck.cobblemon$setMountedPokemon(pokemonEntity);
state.isCrouching = false;
} else {
duck.cobblemon$setMountedPlayer(null);
duck.cobblemon$setMountedPokemon(null);
}
}
@ModifyExpressionValue(
method = "getRenderOffset(Lnet/minecraft/client/renderer/entity/state/AvatarRenderState;)Lnet/minecraft/world/phys/Vec3;",
at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/entity/state/HumanoidRenderState;isCrouching:Z", opcode = Opcodes.GETFIELD)
)
private boolean cobblemon$disableMountedCrouchOffset(boolean isCrouching, AvatarRenderState state) {
AvatarRenderStateDuck duck = (AvatarRenderStateDuck) state;
if (duck.cobblemon$getMountedPlayer() != null && duck.cobblemon$getMountedPokemon() != null) {
return false;
}
return isCrouching;
}
}
@@ -12,36 +12,33 @@ import com.cobblemon.mod.common.api.riding.Rideable;
import com.cobblemon.mod.common.client.MountedPokemonAnimationRenderController;
import com.cobblemon.mod.common.client.render.camera.MountedCameraRenderer;
import com.cobblemon.mod.common.duck.CameraDuck;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
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;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Camera.class)
public abstract class CameraMixin implements CameraDuck {
@Shadow private float eyeHeight;
@Shadow private float eyeHeightOld;
@Shadow private Level level;
@Shadow private BlockGetter level;
@Shadow private Entity entity;
@Final @Shadow private Vector3f forwards;
@Final @Shadow private Vector3f up;
@Final @Shadow private Vector3f left;
@Shadow private float yRot;
@Shadow private float xRot;
@Shadow private Vec3 position;
@Shadow @Final private BlockPos.MutableBlockPos blockPosition;
@Shadow private int matrixPropertiesDirty;
@Shadow protected abstract void setPosition(Vec3 pos);
@Override public BlockGetter cobblemon$getLevel() {
return level;
@@ -63,19 +60,15 @@ public abstract class CameraMixin implements CameraDuck {
@Override public float cobblemon$getYRot() { return yRot; }
@Override public void cobblemon$setYRot(float yRot) { this.yRot = yRot; }
@Override public void cobblemon$markDirty() { this.matrixPropertiesDirty |= 3; }
@Inject(method = "setPosition(DDD)V", at = @At("HEAD"), cancellable = true)
private void cobblemon$positionCamera(double x, double y, double z, CallbackInfo ci) {
if (this.entity == null) return;
Entity entity = this.entity;
@WrapOperation(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;setPosition(DDD)V"))
public void cobblemon$positionCamera(Camera instance, double x, double y, double z, Operation<Void> original, @Local(ordinal = 1, argsOnly = true) boolean thirdPersonReverse) {
Entity entity = instance.getEntity();
Entity vehicle = entity.getVehicle();
boolean thirdPersonReverse = Minecraft.getInstance().options.getCameraType().isMirrored();
MountedPokemonAnimationRenderController.INSTANCE.reset();
if (vehicle instanceof Rideable) {
Vec3 ridePos = MountedCameraRenderer.INSTANCE.getCameraPosition(
(Camera) (Object) this,
if(vehicle instanceof Rideable){
Vec3 position = MountedCameraRenderer.INSTANCE.getCameraPosition(
instance,
entity,
vehicle,
thirdPersonReverse,
@@ -83,17 +76,14 @@ public abstract class CameraMixin implements CameraDuck {
eyeHeightOld
);
if (ridePos != null) {
// Directly set the position field instead of calling setPosition(Vec3)
this.position = ridePos;
this.blockPosition.set(ridePos.x, ridePos.y, ridePos.z);
ci.cancel();
if(position != null) {
setPosition(position);
return;
}
}
// reset the rotation values if it is now not being ridden.
MountedCameraRenderer.INSTANCE.setSmoothRotation(null);
original.call(instance, x, y, z);
}
}
@@ -0,0 +1,85 @@
/*
* 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.CobblemonRecipeCategories;
import com.cobblemon.mod.common.item.crafting.CookingPotBookCategory;
import com.cobblemon.mod.common.item.crafting.CookingPotRecipe;
import com.cobblemon.mod.common.item.crafting.CookingPotRecipeBase;
import com.cobblemon.mod.common.item.crafting.CookingPotShapelessRecipe;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import net.minecraft.client.ClientRecipeBook;
import net.minecraft.client.RecipeBookCategories;
import net.minecraft.client.gui.screens.recipebook.RecipeCollection;
import net.minecraft.core.RegistryAccess;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeHolder;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List;
import java.util.Map;
@Mixin(ClientRecipeBook.class)
public abstract class ClientRecipeBookMixin {
@Shadow
protected static Map<RecipeBookCategories, List<List<RecipeHolder<?>>>> categorizeAndGroupRecipes(Iterable<RecipeHolder<?>> recipes) {
return null;
}
@Shadow
private Map<RecipeBookCategories, List<RecipeCollection>> collectionsByTab;
@Shadow
private List<RecipeCollection> allCollections;
@Inject(method = "getCategory", at = @At(value = "HEAD"), cancellable = true)
private static void addCustomCategory(RecipeHolder<?> recipe, CallbackInfoReturnable<RecipeBookCategories> cir) {
Recipe<?> recipe2 = recipe.value();
if (recipe2 instanceof CookingPotRecipeBase) {
CookingPotBookCategory category = ((CookingPotRecipeBase) recipe2).getCategory();
RecipeBookCategories var7;
switch (category) {
case MISC -> var7 = CobblemonRecipeCategories.COOKING_POT_MISC.toVanillaCategory();
case FOODS -> var7 = CobblemonRecipeCategories.COOKING_POT_FOODS.toVanillaCategory();
case MEDICINES -> var7 = CobblemonRecipeCategories.COOKING_POT_MEDICINES.toVanillaCategory();
case COMPLEX_DISHES -> var7 = CobblemonRecipeCategories.COOKING_POT_COMPLEX_DISHES.toVanillaCategory();
default -> throw new MatchException(null, null);
}
cir.setReturnValue(var7);
}
}
@Inject(method = "setupCollections", at = @At("RETURN"))
private void addCustomAggregateCategories(Iterable<RecipeHolder<?>> recipes, RegistryAccess registryAccess, CallbackInfo ci) {
Map<RecipeBookCategories, List<List<RecipeHolder<?>>>> map = categorizeAndGroupRecipes(recipes);
Map<RecipeBookCategories, List<RecipeCollection>> map2 = Maps.newHashMap();
ImmutableList.Builder<RecipeCollection> builder = ImmutableList.builder();
map.forEach((recipeBookCategories, list) -> {
List<RecipeCollection> collections = list.stream()
.map(listx -> new RecipeCollection(registryAccess, listx))
.peek(builder::add)
.collect(ImmutableList.toImmutableList());
map2.put(recipeBookCategories, collections);
});
RecipeBookCategories.AGGREGATE_CATEGORIES.forEach((recipeBookCategories, list) -> map2.put(recipeBookCategories, (List) list.stream().flatMap((recipeBookCategoriesx) -> ((List) map2.getOrDefault(recipeBookCategoriesx, ImmutableList.of())).stream()).collect(ImmutableList.toImmutableList())));
CobblemonRecipeCategories.Companion.getCustomAggregateCategories().forEach((recipeBookCategories, list) -> map2.put(recipeBookCategories, (List) list.stream().flatMap((recipeBookCategoriesx) -> ((List) map2.getOrDefault(recipeBookCategoriesx, ImmutableList.of())).stream()).collect(ImmutableList.toImmutableList())));
this.collectionsByTab = ImmutableMap.copyOf(map2);
this.allCollections = builder.build();
}
}
@@ -1,32 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.client;
import com.mojang.blaze3d.platform.cursor.CursorType;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen;
import net.minecraft.world.item.CreativeModeTab;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(CreativeModeInventoryScreen.class)
public abstract class CreativeModeInventoryScreenMixin {
@Redirect(
method = "renderTabButton",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/gui/GuiGraphicsExtractor;requestCursor(Lcom/mojang/blaze3d/platform/cursor/CursorType;)V"
)
)
private void cobblemon$skipCreativeTabCursor(GuiGraphicsExtractor guiGraphics, CursorType cursorType, GuiGraphicsExtractor context, int mouseX, int mouseY, CreativeModeTab tab) {
// 1.21.1 had no special cursor on creative tab hover; keep the arrow cursor for tab icons.
}
}
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.client.gui.ScrollingWidget;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import net.minecraft.client.gui.components.AbstractSelectionList;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@Mixin(AbstractSelectionList.class)
public abstract class EntryListWidgetMixin {
@SuppressWarnings("ConstantValue")
@ModifyExpressionValue(method = "getEntryAtPosition", at = @At(value = "CONSTANT", args = {"intValue=4"}))
public int cobblemon$adjustOnlyIfNecessary(int original) {
if(ScrollingWidget.class.isInstance(this)) {
return 0;
}
return original;
}
}
@@ -49,14 +49,14 @@ public class GameRendererMixin {
}
@ModifyArg(
method = "pick",
method = "pick(Lnet/minecraft/world/entity/Entity;DDF)Lnet/minecraft/world/phys/HitResult;",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/phys/EntityHitResult;getEntity()Lnet/minecraft/world/entity/Entity;"
target = "Lnet/minecraft/world/entity/projectile/ProjectileUtil;getEntityHitResult(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/AABB;Ljava/util/function/Predicate;D)Lnet/minecraft/world/phys/EntityHitResult;"
),
index = 4
)
private Predicate<Entity> filterPokemonVehicle(Predicate<Entity> original, @Local Entity entity) {
private Predicate<Entity> filterPokemonVehicle(Predicate<Entity> original, @Local(ordinal = 0, argsOnly = true) Entity entity) {
return (entityX) -> !(entity.getVehicle() == entityX && entityX instanceof PokemonEntity) && original.test(entityX);
}
@@ -8,17 +8,15 @@
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.client.render.player.MountedPlayerRenderer;
import com.cobblemon.mod.common.duck.AvatarRenderStateDuck;
import com.cobblemon.mod.common.duck.LivingEntityRenderStateDuck;
import com.cobblemon.mod.common.entity.PoseType;
import com.cobblemon.mod.common.duck.RidePassenger;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.entity.state.AvatarRenderState;
import net.minecraft.client.renderer.entity.state.HumanoidRenderState;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -43,75 +41,59 @@ public class HumanoidModelMixin {
@Shadow @Final
public ModelPart body;
@Inject(
method = "setupAnim(Lnet/minecraft/client/renderer/entity/state/HumanoidRenderState;)V",
at = @At("TAIL")
)
public void cobblemon$animateRiders(HumanoidRenderState renderState, CallbackInfo ci) {
@Inject(method = "setupAnim*", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/model/geom/ModelPart;copyFrom(Lnet/minecraft/client/model/geom/ModelPart;)V", shift = At.Shift.BEFORE))
public void cobblemon$animateRiders(
LivingEntity entity,
float limbSwing,
float limbSwingAmount,
float ageInTicks,
float netHeadYaw,
float headPitch,
CallbackInfo ci
) {
MountedPlayerRenderer.shouldApplyRootAnimation = false;
if (!(renderState instanceof AvatarRenderState avatarRenderState)) {
return;
if (MountedPlayerRenderer.relevantPartsByName.size() <= 1) {
MountedPlayerRenderer.relevantPartsByName.put("arm_left", leftArm);
MountedPlayerRenderer.relevantPartsByName.put("arm_right", rightArm);
MountedPlayerRenderer.relevantPartsByName.put("leg_left", leftLeg);
MountedPlayerRenderer.relevantPartsByName.put("leg_right", rightLeg);
MountedPlayerRenderer.relevantPartsByName.put("head", head);
MountedPlayerRenderer.relevantPartsByName.put("hat", hat);
MountedPlayerRenderer.relevantPartsByName.put("torso", body);
}
AvatarRenderStateDuck duck = (AvatarRenderStateDuck) avatarRenderState;
LivingEntityRenderStateDuck livingDuck = (LivingEntityRenderStateDuck) avatarRenderState;
AbstractClientPlayer player = duck.cobblemon$getMountedPlayer();
PokemonEntity pokemonEntity = duck.cobblemon$getMountedPokemon();
if (player == null || pokemonEntity == null) {
return;
Entity vehicle = entity.getVehicle();
if (vehicle instanceof PokemonEntity pokemonEntity && entity instanceof OrientationControllable) {
var shouldRotatePlayerHead = pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) ->
behaviour.shouldRotateRiderHead(settings, state, pokemonEntity)
);
// If the player is on a rollable ride then use the ride local rotations to rotate the head
// This is to allow the player head to face the correct direction when "freelooking"
// TODO: find a way for this to work on built jars without borking head rotations.
// if (entity instanceof RidePassenger playerRotater &&
// vehicle instanceof OrientationControllable controller &&
// controller.getOrientationController().isActive()) {
// this.head.xRot = playerRotater.cobblemon$getRideXRot();
// headPitch = playerRotater.cobblemon$getRideXRot();
// this.head.yRot = playerRotater.cobblemon$getRideYRot();
// netHeadYaw = playerRotater.cobblemon$getRideYRot();
// }
if (!shouldRotatePlayerHead) {
netHeadYaw = 0f;
headPitch = 0f;
if (this.head != null) {
this.head.yRot = 0f;
this.head.xRot = 0f;
}
}
if (!(entity instanceof AbstractClientPlayer player)) return;
MountedPlayerRenderer.shouldApplyRootAnimation = true;
MountedPlayerRenderer.INSTANCE.animate((HumanoidModel<AbstractClientPlayer>)(Object)this, pokemonEntity, player, netHeadYaw, headPitch, ageInTicks, limbSwing, limbSwingAmount);
}
int seatIndex = livingDuck.cobblemon$getMountedSeatIndex();
String seatLocator = livingDuck.cobblemon$getMountedSeatLocator();
PoseType poseType = livingDuck.cobblemon$getMountedPoseType();
if (seatIndex < 0 || poseType == null) {
return;
}
MountedPlayerRenderer.relevantPartsByName.put("arm_left", leftArm);
MountedPlayerRenderer.relevantPartsByName.put("arm_right", rightArm);
MountedPlayerRenderer.relevantPartsByName.put("leg_left", leftLeg);
MountedPlayerRenderer.relevantPartsByName.put("leg_right", rightLeg);
MountedPlayerRenderer.relevantPartsByName.put("head", head);
MountedPlayerRenderer.relevantPartsByName.put("hat", hat);
MountedPlayerRenderer.relevantPartsByName.put("torso", body);
Entity vehicle = player.getVehicle();
if (!(vehicle instanceof PokemonEntity)) {
return;
}
var shouldRotatePlayerHead = pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) ->
behaviour.shouldRotateRiderHead(settings, state, pokemonEntity)
);
float netHeadYaw = avatarRenderState.yRot;
float headPitch = avatarRenderState.xRot;
if (!shouldRotatePlayerHead) {
netHeadYaw = 0f;
headPitch = 0f;
this.head.yRot = 0f;
this.head.xRot = 0f;
}
MountedPlayerRenderer.INSTANCE.animate(
(HumanoidModel<?>)(Object)this,
pokemonEntity,
player,
avatarRenderState,
seatIndex,
seatLocator,
poseType,
netHeadYaw,
headPitch,
avatarRenderState.ageInTicks,
avatarRenderState.walkAnimationPos,
avatarRenderState.walkAnimationSpeed
);
MountedPlayerRenderer.shouldApplyRootAnimation = true;
}
}
}
@@ -1,62 +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.item.PokeBallItem;
import com.cobblemon.mod.common.item.PokedexItem;
import net.minecraft.client.renderer.entity.ItemEntityRenderer;
import net.minecraft.client.renderer.entity.state.ItemEntityRenderState;
import net.minecraft.client.renderer.item.ItemModelResolver;
import net.minecraft.core.component.DataComponents;
import net.minecraft.resources.Identifier;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ItemEntityRenderer.class)
public class ItemEntityRendererMixin {
@Shadow @Final private ItemModelResolver itemModelResolver;
@Inject(method = "extractRenderState", at = @At("TAIL"))
private void cobblemon$overrideDroppedItemModel(ItemEntity entity, ItemEntityRenderState state, float partialTick, CallbackInfo ci) {
Identifier modelId = cobblemon$getGroundModel(entity.getItem());
if (modelId == null) {
return;
}
ItemStack renderStack = entity.getItem().copy();
renderStack.set(DataComponents.ITEM_MODEL, modelId);
this.itemModelResolver.updateForNonLiving(state.item, renderStack, ItemDisplayContext.GROUND, entity);
}
@Unique
private static Identifier cobblemon$getGroundModel(ItemStack stack) {
if (stack.getItem() instanceof PokeBallItem pokeBallItem) {
return cobblemon$asStandaloneModel(pokeBallItem.getPokeBall().getModel3d());
}
if (stack.getItem() instanceof PokedexItem pokedexItem) {
return cobblemon$asStandaloneModel(pokedexItem.getType().getItemModelPath("off"));
}
return null;
}
@Unique
private static Identifier cobblemon$asStandaloneModel(Identifier modelId) {
return modelId.withPath(path -> path.startsWith("item/") ? path.substring("item/".length()) : path);
}
}
@@ -9,27 +9,16 @@
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.item.PokeBallItem;
import com.cobblemon.mod.common.item.PokedexItem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.ItemInHandRenderer;
import net.minecraft.client.renderer.SubmitNodeCollector;
import net.minecraft.client.renderer.item.ItemModelResolver;
import net.minecraft.client.renderer.item.ItemStackRenderState;
import net.minecraft.core.component.DataComponents;
import net.minecraft.resources.Identifier;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import net.minecraft.client.renderer.texture.OverlayTexture;
import org.spongepowered.asm.mixin.Final;
import org.joml.Quaternionf;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
@@ -37,10 +26,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ItemInHandRenderer.class)
public class ItemInHandRendererMixin {
@Shadow @Final private ItemModelResolver itemModelResolver;
@Inject(method = "renderArmWithItem", at = @At(value = "HEAD"), cancellable = true)
private void cobblemon$renderArmWithItem(AbstractClientPlayer abstractClientPlayer, float f, float g, InteractionHand interactionHand, float h, ItemStack itemStack, float i, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int j, CallbackInfo ci) {
private void cobblemon$renderArmWithItem(AbstractClientPlayer abstractClientPlayer, float f, float g, InteractionHand interactionHand, float h, ItemStack itemStack, float i, PoseStack poseStack, MultiBufferSource multiBufferSource, int j, CallbackInfo ci) {
if (abstractClientPlayer.isUsingItem() && abstractClientPlayer.getUseItem().getItem() instanceof PokedexItem) {
ci.cancel();
}
@@ -49,58 +36,10 @@ public class ItemInHandRendererMixin {
}
}
@Inject(method = "renderItem", at = @At("HEAD"), cancellable = true)
private void cobblemon$renderItem(LivingEntity entity, ItemStack stack, ItemDisplayContext displayContext, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int light, CallbackInfo ci) {
Identifier modelId = cobblemon$getHeldModel(stack, entity, displayContext);
if (modelId == null) {
return;
}
ItemStack renderStack = stack.copy();
renderStack.set(DataComponents.ITEM_MODEL, modelId);
ItemStackRenderState renderState = new ItemStackRenderState();
this.itemModelResolver.updateForTopItem(renderState, renderStack, displayContext, entity.level(), entity, entity.getId() + displayContext.ordinal());
renderState.submit(poseStack, submitNodeCollector, light, OverlayTexture.NO_OVERLAY, 0);
ci.cancel();
}
@Redirect(method = "renderHandsWithItems", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;mulPose(Lorg/joml/Quaternionf;)V"))
private void cobblemon$renderHandswithItems(PoseStack instance, Quaternionf quaternion) {
if (!(Minecraft.getInstance().player != null && Minecraft.getInstance().player.getVehicle() instanceof OrientationControllable controllable && controllable.getOrientationController().isActive())) {
instance.mulPose(quaternion);
}
}
@Unique
private static Identifier cobblemon$getHeldModel(ItemStack stack, LivingEntity entity, ItemDisplayContext displayContext) {
if (!cobblemon$isHandContext(displayContext)) {
return null;
}
if (stack.getItem() instanceof PokeBallItem pokeBallItem) {
return cobblemon$asStandaloneModel(pokeBallItem.getPokeBall().getModel3d());
}
if (stack.getItem() instanceof PokedexItem pokedexItem) {
boolean isScanModel = entity instanceof AbstractClientPlayer && entity.getUseItem() == stack && entity.isUsingItem();
boolean canOpenScreen = (entity.getOffhandItem() == stack && !(entity.getMainHandItem().getItem() instanceof PokedexItem)) || entity.getMainHandItem() == stack;
return cobblemon$asStandaloneModel(pokedexItem.getType().getItemModelPath(isScanModel ? "scanning" : (canOpenScreen ? null : "off")));
}
return null;
}
@Unique
private static boolean cobblemon$isHandContext(ItemDisplayContext displayContext) {
return displayContext == ItemDisplayContext.FIRST_PERSON_LEFT_HAND
|| displayContext == ItemDisplayContext.FIRST_PERSON_RIGHT_HAND
|| displayContext == ItemDisplayContext.THIRD_PERSON_LEFT_HAND
|| displayContext == ItemDisplayContext.THIRD_PERSON_RIGHT_HAND;
}
@Unique
private static Identifier cobblemon$asStandaloneModel(Identifier modelId) {
return modelId.withPath(path -> path.startsWith("item/") ? path.substring("item/".length()) : path);
}
}
@@ -0,0 +1,103 @@
/*
* 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.Cobblemon;
import com.cobblemon.mod.common.ModAPI;
import com.cobblemon.mod.common.item.PokeBallItem;
import com.cobblemon.mod.common.item.PokedexItem;
import com.cobblemon.mod.common.item.WearableItem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.ItemModelShaper;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
/*
I think it would be nice to maybe use the existing mixin we have for custom item rendering [BuiltinModelItemRendererMixin]
Obviously that would require changes. Potentially each item renderer defines what modes it overrides for?
*/
@Mixin(ItemRenderer.class)
public abstract class ItemRendererMixin {
// ignore the hint saying implmentation is never null, if something crashes then it is null and causes red herrings
@Unique private final String MODEL_PATH = (Cobblemon.implementation != null && Cobblemon.implementation.getModAPI() == ModAPI.FABRIC) ? "fabric_resource" : "standalone";
@Shadow @Final private ItemModelShaper itemModelShaper;
@Shadow public abstract void render(ItemStack stack, ItemDisplayContext renderMode, boolean leftHanded, PoseStack matrices, MultiBufferSource vertexConsumers, int light, int overlay, BakedModel model);
@Inject(
method = "render(Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemDisplayContext;ZLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;IILnet/minecraft/client/resources/model/BakedModel;)V",
at = @At("HEAD"),
cancellable = true
)
private void cobblemon$overrideItemModel(ItemStack stack, ItemDisplayContext renderMode, boolean leftHanded, PoseStack matrices, MultiBufferSource multiBufferSource, int light, int overlay, BakedModel model, CallbackInfo ci) {
boolean shouldBe2d = renderMode == ItemDisplayContext.GUI || renderMode == ItemDisplayContext.FIXED;
ResourceLocation resourceLocation = null;
if (shouldBe2d) {
if (stack.getItem() instanceof PokeBallItem pokeBallItem) resourceLocation = pokeBallItem.getPokeBall().getModel2d();
else if (stack.getItem() instanceof PokedexItem pokedexItem) resourceLocation = pokedexItem.getType().getItemSpritePath();
}
if (renderMode != ItemDisplayContext.HEAD && stack.getItem() instanceof WearableItem wearableItem) resourceLocation = wearableItem.getModel2d();
if (resourceLocation != null) {
BakedModel replacementModel = this.itemModelShaper.getModelManager().getModel(new ModelResourceLocation(resourceLocation, "inventory"));
if (!cobblemon$isSameModel(model, replacementModel)) {
ci.cancel();
render(stack, renderMode, leftHanded, matrices, multiBufferSource, light, overlay, replacementModel);
}
}
}
@Inject(method = "getModel", at = @At("HEAD"), cancellable = true)
private void cobblemon$getItemModel(ItemStack stack, Level world, LivingEntity entity, int seed, CallbackInfoReturnable<BakedModel> cir) {
ResourceLocation resourceLocation = null;
if (stack.getItem() instanceof PokeBallItem pokeBallItem) resourceLocation = pokeBallItem.getPokeBall().getModel3d();
else if (stack.getItem() instanceof PokedexItem pokedexItem) {
boolean isScanModel = entity instanceof Player && entity.getUseItem() == stack && entity.isUsingItem();
boolean canOpenScreen = entity != null && ((entity.getOffhandItem() == stack && !(entity.getMainHandItem().getItem() instanceof PokedexItem)) || entity.getMainHandItem() == stack);
resourceLocation = pokedexItem.getType().getItemModelPath(isScanModel ? "scanning" : (canOpenScreen ? null : "off"));
}
else if (stack.getItem() instanceof WearableItem wearableItem) resourceLocation = wearableItem.getModel3d();
if (resourceLocation != null) {
BakedModel model = this.itemModelShaper.getModelManager().getModel(new ModelResourceLocation(resourceLocation, MODEL_PATH));
ClientLevel clientWorld = world instanceof ClientLevel ? (ClientLevel) world : null;
BakedModel overriddenModel = model.getOverrides().resolve(model, stack, clientWorld, entity, seed);
cir.setReturnValue(overriddenModel == null ? this.itemModelShaper.getModelManager().getMissingModel() : overriddenModel);
}
}
// this method aims to cover an issue with modernfixes and it's "dynamic resource" causing the usual .equals check to always fail, resulting in a StackOverflow
// this falls back to comparing the model contents (e.g. location of the texture, width and height)
@Unique
private static boolean cobblemon$isSameModel(BakedModel original, BakedModel replacement) {
return original.equals(replacement) ||
(original.getParticleIcon().contents().name().equals(replacement.getParticleIcon().contents().name()) &&
original.getParticleIcon().contents().width() == replacement.getParticleIcon().contents().width() &&
original.getParticleIcon().contents().height() == replacement.getParticleIcon().contents().height());
}
}
@@ -1,85 +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.duck.LivingEntityRenderStateDuck;
import com.cobblemon.mod.common.entity.PoseType;
import net.minecraft.client.renderer.entity.state.LivingEntityRenderState;
import net.minecraft.world.entity.LivingEntity;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
@Mixin(LivingEntityRenderState.class)
public class LivingEntityRenderStateMixin implements LivingEntityRenderStateDuck {
@Unique
private @Nullable LivingEntity cobblemon$mountedEntity;
@Unique
private float cobblemon$mountedPartialTick;
@Unique
private int cobblemon$mountedSeatIndex = -1;
@Unique
private @Nullable String cobblemon$mountedSeatLocator;
@Unique
private @Nullable PoseType cobblemon$mountedPoseType;
@Override
public @Nullable LivingEntity cobblemon$getMountedEntity() {
return this.cobblemon$mountedEntity;
}
@Override
public void cobblemon$setMountedEntity(@Nullable LivingEntity entity) {
this.cobblemon$mountedEntity = entity;
}
@Override
public float cobblemon$getMountedPartialTick() {
return this.cobblemon$mountedPartialTick;
}
@Override
public void cobblemon$setMountedPartialTick(float partialTick) {
this.cobblemon$mountedPartialTick = partialTick;
}
@Override
public int cobblemon$getMountedSeatIndex() {
return this.cobblemon$mountedSeatIndex;
}
@Override
public void cobblemon$setMountedSeatIndex(int seatIndex) {
this.cobblemon$mountedSeatIndex = seatIndex;
}
@Override
public @Nullable String cobblemon$getMountedSeatLocator() {
return this.cobblemon$mountedSeatLocator;
}
@Override
public void cobblemon$setMountedSeatLocator(@Nullable String seatLocator) {
this.cobblemon$mountedSeatLocator = seatLocator;
}
@Override
public @Nullable PoseType cobblemon$getMountedPoseType() {
return this.cobblemon$mountedPoseType;
}
@Override
public void cobblemon$setMountedPoseType(@Nullable PoseType poseType) {
this.cobblemon$mountedPoseType = poseType;
}
}
@@ -8,123 +8,30 @@
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.client.render.ClientPlayerIcon;
import com.cobblemon.mod.common.client.render.entity.MountedLivingEntityRenderer;
import com.cobblemon.mod.common.duck.LivingEntityRenderStateDuck;
import com.cobblemon.mod.common.entity.PoseType;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.item.WearableItem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.SubmitNodeCollector;
import net.minecraft.client.model.EntityModel;
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
import net.minecraft.client.renderer.entity.state.AvatarRenderState;
import net.minecraft.client.renderer.entity.state.LivingEntityRenderState;
import net.minecraft.client.renderer.item.ItemModelResolver;
import net.minecraft.client.renderer.state.level.CameraRenderState;
import net.minecraft.core.component.DataComponents;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(LivingEntityRenderer.class)
public class LivingEntityRendererMixin {
@Shadow @Final protected ItemModelResolver itemModelResolver;
@Inject(
method = "extractRenderState",
at = @At("TAIL")
)
private void cobblemon$captureMountedEntity(LivingEntity entity, LivingEntityRenderState state, float partialTick, CallbackInfo ci) {
LivingEntityRenderStateDuck duck = (LivingEntityRenderStateDuck) state;
if (entity.isPassenger() && entity.getVehicle() instanceof PokemonEntity) {
PokemonEntity pokemonEntity = (PokemonEntity) entity.getVehicle();
int seatIndex = pokemonEntity.getPassengers().indexOf(entity);
String seatLocator = null;
PoseType poseType = pokemonEntity.getCurrentPoseType();
if (seatIndex >= 0 && seatIndex < pokemonEntity.getSeats().size()) {
seatLocator = pokemonEntity.getSeats().get(seatIndex).getLocator();
if (seatLocator == null) {
seatLocator = "seat_" + (seatIndex + 1);
}
} else {
seatIndex = -1;
}
duck.cobblemon$setMountedEntity(entity);
duck.cobblemon$setMountedPartialTick(partialTick);
duck.cobblemon$setMountedSeatIndex(seatIndex);
duck.cobblemon$setMountedSeatLocator(seatLocator);
duck.cobblemon$setMountedPoseType(poseType);
} else {
duck.cobblemon$setMountedEntity(null);
duck.cobblemon$setMountedPartialTick(0.0F);
duck.cobblemon$setMountedSeatIndex(-1);
duck.cobblemon$setMountedSeatLocator(null);
duck.cobblemon$setMountedPoseType(null);
}
ItemStack headItem = entity.getItemBySlot(EquipmentSlot.HEAD);
if (headItem.getItem() instanceof WearableItem wearableItem) {
ItemStack renderHeadItem = headItem.copy();
renderHeadItem.set(DataComponents.ITEM_MODEL, wearableItem.getModel3d().withPath(path -> path.startsWith("item/") ? path.substring("item/".length()) : path));
this.itemModelResolver.updateForLiving(state.headItem, renderHeadItem, ItemDisplayContext.HEAD, entity);
}
}
public class LivingEntityRendererMixin<T extends LivingEntity, M extends EntityModel<T>> {
@Inject(
method = "setupRotations",
at = @At("HEAD")
)
private void cobblemon$modifyRoll(LivingEntityRenderState state, PoseStack poseStack, float bodyRot, float scale, CallbackInfo ci) {
LivingEntityRenderStateDuck duck = (LivingEntityRenderStateDuck) state;
LivingEntity entity = duck.cobblemon$getMountedEntity();
if (entity == null || !(entity.getVehicle() instanceof PokemonEntity pokemonEntity)) {
return;
}
MountedLivingEntityRenderer.INSTANCE.render(
entity,
pokemonEntity,
poseStack,
state.walkAnimationPos,
bodyRot,
duck.cobblemon$getMountedPartialTick(),
scale
);
}
@Inject(
method = "submit",
at = @At("TAIL")
)
private void cobblemon$renderPlayerIcon(
LivingEntityRenderState state,
PoseStack poseStack,
SubmitNodeCollector submitNodeCollector,
CameraRenderState cameraRenderState,
CallbackInfo ci
) {
if (!(state instanceof AvatarRenderState avatarState)) {
return;
}
var level = Minecraft.getInstance().level;
if (level == null) {
return;
}
var entity = level.getEntity(avatarState.id);
if (entity instanceof Player player) {
ClientPlayerIcon.Companion.onRenderPlayer(player);
private void cobblemon$modifyRoll(LivingEntity entity, PoseStack poseStack, float bob, float yBodyRot, float partialTick, float scale, CallbackInfo ci) {
if (entity.isPassenger()) {
var vehicle = entity.getVehicle();
if (vehicle instanceof PokemonEntity pokemonEntity) {
MountedLivingEntityRenderer.INSTANCE.render(entity, pokemonEntity, poseStack, bob, yBodyRot, partialTick, scale);
}
}
}
}
@@ -29,7 +29,7 @@ import net.minecraft.client.CameraType;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.player.ClientInput;
import net.minecraft.client.player.Input;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
@@ -64,7 +64,7 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
@Shadow
private float jumpRidingScale;
@Shadow public ClientInput input;
@Shadow public Input input;
@Shadow private int autoJumpTime;
@@ -88,7 +88,6 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
@Inject(method = "rideTick", at = @At("HEAD"))
private void cobblemon$updateOrientationControllerRideTick(CallbackInfo ci) {
if (Minecraft.getInstance().player != (Object)this) return;
var driver = (LocalPlayer)(Object)this;
var vehicle = driver.getVehicle();
if (!(this.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
@@ -121,6 +120,7 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
Vector3f lastSentDriverInput = ((PlayerDuck)this).getLastSentDriverInput();
if (driverInput.equals(lastSentDriverInput)) return;
((PlayerDuck)this).setLastSentDriverInput(driverInput);
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateDriverInputPacket(driverInput));
}
@@ -142,6 +142,7 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
cobblemon$lastRideYRot != rideYRot ||
cobblemon$lastRideEyePos != rideEyePos
) {
// Update 'last' values
cobblemon$lastRideXRot = rideXRot;
cobblemon$lastRideYRot = rideYRot;
@@ -187,26 +188,22 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
@Inject(method = "aiStep", at = @At("HEAD"))
private void cobblemon$aiStep(CallbackInfo ci) {
boolean jumpPressed = this.input.keyPresses.jump();
this.cobblemon$isDoubleJumping = false;
this.cobblemon$isJumping = jumpPressed;
this.cobblemon$isJumping = this.input.jumping;
}
@Inject(method = "aiStep", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;isSprinting()Z", shift = At.Shift.BEFORE))
private void cobblemon$updateDoubleJumping(CallbackInfo ci) {
if (!this.cobblemon$isJumping && this.input.keyPresses.jump() && this.autoJumpTime <= 0 && !this.isSwimming()) {
PokemonEntity pokemonEntity = this.getVehicle() instanceof PokemonEntity vehiclePokemon ? vehiclePokemon : null;
if (!this.cobblemon$isJumping && this.input.jumping && this.autoJumpTime <= 0 && !this.isSwimming()) {
if (this.cobblemon$survivalJumpTriggerTime != 0) {
this.cobblemon$isDoubleJumping = true;
this.cobblemon$survivalJumpTriggerTime = 0;
} else {
this.cobblemon$survivalJumpTriggerTime = 12;
if (pokemonEntity != null) {
this.cobblemon$isDoubleJumping = true;
this.cobblemon$survivalJumpTriggerTime = 0;
}
}
} else if (this.cobblemon$survivalJumpTriggerTime > 0) {
else {
this.cobblemon$survivalJumpTriggerTime = 12;
}
}
else if (this.cobblemon$survivalJumpTriggerTime > 0) {
this.cobblemon$survivalJumpTriggerTime--;
}
}
@@ -0,0 +1,49 @@
/*
* 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.client.CobblemonBakingOverrides;
import java.util.List;
import java.util.Map;
import net.minecraft.client.color.block.BlockColors;
import net.minecraft.client.renderer.block.model.BlockModel;
import net.minecraft.client.resources.model.BlockStateModelLoader;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.client.resources.model.UnbakedModel;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.profiling.ProfilerFiller;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ModelBakery.class)
public abstract class ModelLoaderMixin {
@Shadow abstract UnbakedModel getModel(ResourceLocation resourceLocation);
@Shadow protected abstract void registerModel(ModelResourceLocation modelId, UnbakedModel unbakedModel);
@Inject(
method = "<init>",
at = @At("TAIL")
)
public void init(BlockColors blockColors,
ProfilerFiller profiler,
Map<ResourceLocation, BlockModel> jsonUnbakedModels,
Map<ResourceLocation, List<BlockStateModelLoader.LoadedJson>> blockStates,
CallbackInfo ci) {
CobblemonBakingOverrides.INSTANCE.getModels().forEach(bakingOverride -> {
var unbakedModel = this.getModel(bakingOverride.getModelLocation());
this.registerModel(bakingOverride.getModelIdentifier(), unbakedModel);
});
}
}
@@ -1,39 +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.client.render.player.MountedPlayerRenderer;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.model.Model;
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(Model.class)
public abstract class ModelMixin {
@Inject(
method = "renderToBuffer(Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;III)V",
at = @At("HEAD")
)
private void cobblemon$applyMountedRootAnimation(
PoseStack poseStack,
VertexConsumer vertexConsumer,
int packedLight,
int packedOverlay,
int colour,
CallbackInfo ci
) {
if ((Object) this instanceof HumanoidModel<?> && MountedPlayerRenderer.shouldApplyRootAnimation) {
MountedPlayerRenderer.INSTANCE.animateRoot(poseStack);
}
}
}
@@ -11,9 +11,12 @@ package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.Cobblemon;
import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.api.orientation.OrientationController;
import com.cobblemon.mod.common.client.CobblemonClient;
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding;
import com.cobblemon.mod.common.client.keybind.keybinds.RidingFreelookBinding;
import com.cobblemon.mod.common.duck.RidePassenger;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext;
import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
import com.llamalad7.mixinextras.sugar.Local;
import com.mojang.blaze3d.Blaze3D;
@@ -24,6 +27,7 @@ import net.minecraft.client.player.LocalPlayer;
import net.minecraft.util.Mth;
import net.minecraft.util.SmoothDouble;
import net.minecraft.world.phys.Vec3;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -31,12 +35,14 @@ import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.cobblemon.mod.common.client.gui.party.PartyTutorialToasts;
import static com.google.common.primitives.Floats.min;
import static net.minecraft.util.Mth.lerp;
@Mixin(MouseHandler.class)
public abstract class MouseHandlerMixin {
@Shadow private double accumulatedScrollY;
@Shadow @Final private Minecraft minecraft;
@Unique SmoothDouble xMouseSmoother = new SmoothDouble();
@@ -61,6 +67,52 @@ public abstract class MouseHandlerMixin {
@Unique private double cobblemon$timeDelta;
@Inject(
method = "onScroll",
at = @At(
value = "FIELD",
target="Lnet/minecraft/client/MouseHandler;accumulatedScrollY:D",
opcode = Opcodes.PUTFIELD,
ordinal = 2,
shift = At.Shift.BEFORE
),
cancellable = true
)
public void cobblemon$scrollParty(long window, double horizontal, double vertical, CallbackInfo ci) {
if (PartySendBinding.INSTANCE.getWasDown()) {
int i = (int) accumulatedScrollY;
if (i > 0) {
accumulatedScrollY -= i;
CobblemonClient.INSTANCE.getStorage().shiftSelected(false);
ci.cancel();
PartySendBinding.INSTANCE.actioned();
PartyTutorialToasts.INSTANCE.onHoldKeyScrollSwitchedSlot();
} else if (i < 0) {
accumulatedScrollY -= i;
CobblemonClient.INSTANCE.getStorage().shiftSelected(true);
ci.cancel();
PartySendBinding.INSTANCE.actioned();
PartyTutorialToasts.INSTANCE.onHoldKeyScrollSwitchedSlot();
}
}
}
@Inject(
method = "onScroll",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/player/Inventory;swapPaint(D)V"
),
cancellable = true
)
public void cobblemon$doPokedexZoom(long window, double horizontal, double vertical, CallbackInfo ci) {
PokedexUsageContext usageContext = CobblemonClient.INSTANCE.getPokedexUsageContext();
if (usageContext.getScanningGuiOpen()) {
usageContext.adjustZoom(vertical);
ci.cancel();
}
}
@WrapWithCondition(
method = "turnPlayer",
at = @At(
@@ -75,10 +127,28 @@ public abstract class MouseHandlerMixin {
@Local(argsOnly = true) double d,
@Local(argsOnly = true) double movementTime
) {
PokedexUsageContext usageContext = CobblemonClient.INSTANCE.getPokedexUsageContext();
boolean returnValue = true;
if (usageContext.getScanningGuiOpen()) {
this.smoothTurnY.reset();
this.smoothTurnX.reset();
var defaultSensitivity = this.minecraft.options.sensitivity().get() * 0.6 + 0.2;
var spyglassSensitivity = Math.pow(defaultSensitivity, 3);
var lookSensitivity = spyglassSensitivity * 8.0;
var sensitivity = lerp(usageContext.getFovMultiplier(), spyglassSensitivity, lookSensitivity);
var yRotationFlip = this.minecraft.options.invertYMouse().get() ? -1 : 1;
player.turn(this.accumulatedDX * sensitivity, (this.accumulatedDY * sensitivity * yRotationFlip));
returnValue = false;
}
var vehicle = player.getVehicle();
if (!(vehicle instanceof PokemonEntity)) return returnValue;
// Clamp player rotation if riding and the vehicle demands it
if (player.isPassenger() && vehicle instanceof PokemonEntity pokeVehicle) {
pokeVehicle.clampPassengerRotation(player);
}
// If the ride is not orientation controllable then return and perform the normal turnPlayer logic
if (!(vehicle instanceof OrientationControllable controllableVehicle) || !controllableVehicle.getOrientationController().isActive()) {
xMouseSmoother.reset();
@@ -0,0 +1,54 @@
/*
* 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.client.render.ClientPlayerIcon;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.model.PlayerModel;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
import 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(PlayerRenderer.class)
public abstract class PlayerRendererMixin extends LivingEntityRenderer<AbstractClientPlayer, PlayerModel<AbstractClientPlayer>> {
public PlayerRendererMixin(EntityRendererProvider.Context context, PlayerModel<AbstractClientPlayer> model, float shadowRadius) {
super(context, model, shadowRadius);
}
@Inject(method = "render", at = @At(value = "TAIL"))
public void renderPlayer(AbstractClientPlayer player, float f, float g, PoseStack poseStack, MultiBufferSource multiBufferSource, int i, CallbackInfo ci) {
ClientPlayerIcon.Companion.onRenderPlayer(player);
}
@WrapOperation(method = "getRenderOffset(Lnet/minecraft/client/player/AbstractClientPlayer;F)Lnet/minecraft/world/phys/Vec3;", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/AbstractClientPlayer;isCrouching()Z"))
private boolean cobblemon$disableCrouchOffset(AbstractClientPlayer instance, Operation<Boolean> original) {
if (instance.isPassenger() && instance.getVehicle() instanceof PokemonEntity) {
return false;
}
return original.call(instance);
}
@Inject(method = "setModelProperties", at = @At("TAIL"))
private void cobblemon$setModelProperties(AbstractClientPlayer player, CallbackInfo ci) {
if (player.isPassenger() && player.getVehicle() instanceof PokemonEntity) {
PlayerModel<AbstractClientPlayer> playerModel = this.getModel();
playerModel.crouching = false;
}
}
}
@@ -0,0 +1,63 @@
/*
* 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.CobblemonRecipeCategories;
import net.minecraft.client.ClientRecipeBook;
import net.minecraft.client.Minecraft;
import net.minecraft.client.RecipeBookCategories;
import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent;
import net.minecraft.client.gui.screens.recipebook.RecipeBookPage;
import net.minecraft.client.gui.screens.recipebook.RecipeBookTabButton;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(RecipeBookComponent.class)
public class RecipeBookComponentMixin {
@Shadow private ClientRecipeBook book;
@Shadow protected Minecraft minecraft;
@Shadow private int width;
@Shadow private int xOffset;
@Shadow private int height;
@Shadow @Final private RecipeBookPage recipeBookPage;
@Inject(method = "updateTabs", at = @At("HEAD"), cancellable = true)
private void customUpdateTabs(CallbackInfo ci) {
RecipeBookComponent instance = (RecipeBookComponent) (Object) this;
int i = (width - 147) / 2 - xOffset - 30;
int j = (height - 166) / 2 + 3;
int k = 27;
int l = 0;
for (RecipeBookTabButton recipeBookTabButton : instance.tabButtons) {
RecipeBookCategories recipeBookCategories = recipeBookTabButton.getCategory();
if (recipeBookCategories != RecipeBookCategories.CRAFTING_SEARCH && recipeBookCategories != RecipeBookCategories.FURNACE_SEARCH && recipeBookCategories != CobblemonRecipeCategories.COOKING_POT_SEARCH.toVanillaCategory()) {
if (recipeBookTabButton.updateVisibility(book)) {
recipeBookTabButton.setPosition(i, j + 27 * l++);
recipeBookTabButton.startAnimation(minecraft);
}
} else {
recipeBookTabButton.visible = true;
recipeBookTabButton.setPosition(i, j + k * l++);
}
}
ci.cancel();
}
}
@@ -0,0 +1,40 @@
/*
* 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 net.minecraft.client.ClientRecipeBook;
import net.minecraft.client.gui.screens.recipebook.RecipeBookTabButton;
import net.minecraft.client.gui.screens.recipebook.RecipeCollection;
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.CallbackInfoReturnable;
import java.util.List;
@Mixin(RecipeBookTabButton.class)
public class RecipeBookTabButtonMixin {
@Inject(method = "updateVisibility", at = @At("HEAD"), cancellable = true)
private void customUpdateVisibility(ClientRecipeBook recipeBook, CallbackInfoReturnable<Boolean> cir) {
RecipeBookTabButton instance = (RecipeBookTabButton) (Object) this;
List<RecipeCollection> list = recipeBook.getCollection(instance.getCategory());
boolean visible = false;
if (list != null) {
for (RecipeCollection recipeCollection : list) {
if (recipeCollection.hasKnownRecipes() && recipeCollection.hasFitting()) {
visible = true;
break;
}
}
}
instance.visible = visible;
cir.setReturnValue(visible);
}
}
@@ -0,0 +1,53 @@
/*
* 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 net.minecraft.client.gui.screens.recipebook.RecipeCollection;
import net.minecraft.stats.RecipeBook;
import net.minecraft.world.entity.player.StackedContents;
import net.minecraft.world.item.crafting.RecipeHolder;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
import java.util.Set;
@Mixin(RecipeCollection.class)
public class RecipeCollectionMixin {
@Shadow @Final private Set<RecipeHolder<?>> fitsDimensions;
@Shadow @Final private Set<RecipeHolder<?>> craftable;
@Shadow @Final private List<RecipeHolder<?>> recipes;
@Inject(method = "canCraft", at = @At("HEAD"), cancellable = true)
private void customCanCraft(StackedContents handler, int width, int height, RecipeBook book, CallbackInfo ci) {
for (RecipeHolder<?> recipeHolder : recipes) {
boolean bl = recipeHolder.value().canCraftInDimensions(width, height) && book.contains(recipeHolder);
if (bl) {
fitsDimensions.add(recipeHolder);
} else {
fitsDimensions.remove(recipeHolder);
}
if (bl && handler.canCraft(recipeHolder.value(), null)) {
craftable.add(recipeHolder);
} else {
craftable.remove(recipeHolder);
}
}
ci.cancel();
}
}
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.client.render.TextClipping;
import net.minecraft.client.gui.Font;
import net.minecraft.network.chat.Style;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@@ -34,13 +35,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
* @author Hiroku
* @since April 18th, 2025
*/
@Mixin(targets = "net.minecraft.client.gui.Font$PreparedTextBuilder")
@Mixin(Font.StringRenderOutput.class)
public class StringRenderOutputMixin {
@Inject(method = "accept", at = @At(value = "HEAD"), cancellable = true)
public void onAccept(int i, Style style, int j, CallbackInfoReturnable<Boolean> cir) {
if (!TextClipping.canDrawAnotherCharacter()) {
cir.setReturnValue(false);
cir.setReturnValue(true);
}
}
}
@@ -1,20 +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.accessor;
import com.mojang.blaze3d.systems.ScissorState;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(GuiGraphicsExtractor.class)
public interface GuiGraphicsExtractorAccessor {
@Accessor
public GuiGraphicsExtractor.ScissorStack getScissorStack();
}
@@ -1,26 +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.accessor;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.renderer.entity.state.HumanoidRenderState;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(HumanoidModel.class)
public interface HumanoidModelAccessor {
@Invoker("poseRightArm")
void cobblemon$invokePoseRightArm(HumanoidRenderState renderState);
@Invoker("poseLeftArm")
void cobblemon$invokePoseLeftArm(HumanoidRenderState renderState);
@Invoker("setupAttackAnimation")
void cobblemon$invokeSetupAttackAnimation(HumanoidRenderState renderState);
}
@@ -1,24 +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.accessor;
import net.minecraft.client.model.EntityModel;
import net.minecraft.client.renderer.entity.layers.RenderLayer;
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
import net.minecraft.client.renderer.entity.state.EntityRenderState;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.List;
@Mixin(LivingEntityRenderer.class)
public interface LivingEntityRendererAccessor<S extends EntityRenderState, M extends EntityModel<? super S>> {
@Accessor("layers")
List<RenderLayer<S, M>> cobblemon$getLayers();
}
@@ -19,7 +19,7 @@ import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
import java.util.function.Function;
@@ -33,7 +33,7 @@ public final class SnapshotWarningMixin {
private final Pattern VERSION = Pattern.compile("^(?<major>\\d+)\\.(?<minor>\\d+)\\.(?<patch>\\d+)$");
@Inject(method = "addInitialScreens", at = @At("TAIL"))
public void cobblemon$addSnapshotWarningScreen(List<Function<Runnable, Screen>> output, CallbackInfoReturnable<Boolean> callback) {
public void cobblemon$addSnapshotWarningScreen(List<Function<Runnable, Screen>> output, CallbackInfo callback) {
if (CobblemonBuildDetails.SNAPSHOT && !this.cobblemon$isAcknowledged() && !SharedConstants.IS_RUNNING_IN_IDE) {
output.add((runnable) -> new SnapshotWarningScreen((acknowledgement, dsa) -> {
if (acknowledgement == SnapshotWarningScreen.Acknowledgement.NO) {
@@ -82,7 +82,7 @@ public abstract class EntityMixin {
@Unique
private void cobblemon$getCustomEyePos(CallbackInfoReturnable<Vec3> cir) {
var entity = (Entity)(Object)this;
if (entity.level().isClientSide()) return;
if (entity.level().isClientSide) return;
if (!(entity instanceof Player player)) return;
if (!(player instanceof RidePassenger ridePassenger)) return;
if (!(player.getVehicle() instanceof OrientationControllable vehicle)) return;
@@ -9,24 +9,18 @@
package com.cobblemon.mod.common.mixin.entity;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.TamableAnimal;
import net.minecraft.world.level.gamerules.GameRule;
import net.minecraft.world.level.Level;
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;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(TamableAnimal.class)
public class TameableEntityMixin {
@Inject(method = "die", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/TamableAnimal;getOwner()Lnet/minecraft/world/entity/LivingEntity;"), cancellable = true)
public void cobblemon$checkIfPokemonBeforeSendingMessage(DamageSource damageSource, CallbackInfo ci, @Local(name = "var4") LivingEntity owner) {
if(((TamableAnimal)(Object)this).level().isClientSide() || (this.getClass().isAssignableFrom(PokemonEntity.class))) {
ci.cancel();
}
@Redirect(method = "die", at = @At(value = "FIELD", target = "Lnet/minecraft/world/level/Level;isClientSide:Z"))
public boolean cobblemon$checkIfPokemonBeforeSendingMessage(Level world) {
return world.isClientSide || (this.getClass().isAssignableFrom(PokemonEntity.class));
}
}
@@ -11,33 +11,33 @@ package com.cobblemon.mod.common.mixin.invoker;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.properties.BlockSetType;
import net.minecraft.world.level.material.MapColor;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@SuppressWarnings("unused")
@Mixin(Blocks.class)
public interface BlocksInvoker {
@Invoker
static BlockBehaviour.Properties callLogProperties(MapColor mapColor, MapColor mapColor2, SoundType soundType) {
@Invoker("log")
static Block createLogBlock(MapColor topMapColor, MapColor sideMapColor) {
throw new UnsupportedOperationException();
}
@Invoker
static BlockBehaviour.Properties callLeavesProperties(SoundType soundType) {
@Invoker("leaves")
static Block createLeavesBlock(SoundType soundGroup) {
throw new UnsupportedOperationException();
}
@Invoker
static BlockBehaviour.Properties callButtonProperties() {
@Invoker("woodenButton")
static Block createWoodenButtonBlock(BlockSetType blockSetType) {
throw new UnsupportedOperationException();
}
@Invoker
static BlockBehaviour.Properties callFlowerPotProperties() {
@Invoker("flowerPot")
static Block createFlowerPotBlock(Block flower) {
throw new UnsupportedOperationException();
}
}
}

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