Compare commits

..
Author SHA1 Message Date
Hiroku 45a9ad866e Fixed heaps of transformations passively activating outside of battle 2026-09-26 18:46:42 +10:00
Hiroku 9c3066e787 Labelled many more forms as temporary 2026-09-20 11:34:59 +10:00
Hiroku eb8598278f Various form change corrections and marked cherrim sunshine as a temporary form in the data 2026-09-20 11:02:04 +10:00
Hiroku 6777c8d57d Merge remote-tracking branch 'origin/main' into form_changes
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/api/molang/function/EvolutionMoLangFunctions.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/molang/function/PokemonMoLangFunctions.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/item/interactive/PPUpItem.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/pokemon/requirements/StatCompareRequirement.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/pokemon/requirements/StatEqualRequirement.kt
#	gradle.properties
2026-09-20 10:23:05 +10:00
Polymeta bf7d40c9b5 Merge branch 'small-jvm-fix' into 'main'
Added JvmField to Some values in Cobblemon Blocks cause it was forgotten

See merge request cable-mc/cobblemon!2419
2026-09-18 18:30:24 +00:00
Polymeta 5abb3d7f97 Merge branch 'fix/molang-delete-variables-fn' into 'main'
fix: reintroduce `delete_variables` general molang fn

See merge request cable-mc/cobblemon!2421
2026-09-18 18:29:23 +00:00
Gitoido 975ad8186a chore: dangling variable 2026-09-18 18:03:41 +00:00
Gitoido 26b6419f04 fix: reintroduce delete_variables general molang fn 2026-09-18 18:00:44 +00:00
Aram 89e43945a3 Edit CobblemonBlocks.kt 2026-09-16 14:25:26 +02:00
Aram bd8dcddf35 Edit CobblemonBlocks.kt 2026-09-16 14:24:31 +02:00
Polymeta dd372f3160 Merge branch 'recipe-booking' into 'main'
Recipe Book Tweaks

Closes #2088

See merge request cable-mc/cobblemon!2418
2026-09-16 10:03:42 +00:00
dhi_holo c56aab28d4 Recipe Book Tweaks
Closes #2088 as well as fixes a lot of similar issues for gameplay consistency
2026-09-16 18:41:05 +10:00
Polymeta 3cdf28ffdd Merge branch 'Chorus-Briar-Fix' into 'main'
I'm never doing an update where I have to keep track of 650+ structure files again

See merge request cable-mc/cobblemon!2414
2026-09-14 21:18:29 +00:00
Slippy c6fb18ea51 I'm never doing an update hwere I have to keep track of 650+ structure files again 2026-09-14 10:48:01 -05:00
Polymeta 2d851cb134 Merge branch 'tm-crafting-corrections' into 'main'
TM Recipes

See merge request cable-mc/cobblemon!2413
2026-09-14 13:03:40 +00:00
dhi_holo f685be0aab TM Recipes
Corrected two incorrect TM recieps, both in the jsons and the spreadsheets
2026-09-14 16:30:06 +10:00
Polymeta 6ab5ad52ec Merge branch 'typegem-advancement-trigger' into 'main'
Adds typegem item advancement trigger

Closes #2086

See merge request cable-mc/cobblemon!2411
2026-09-13 20:58:08 +00:00
PieDuck 079b2ae766 Merge branch 'typegem-advancement-trigger' of https://gitlab.com/dmnaru/cobblemon into typegem-advancement-trigger 2026-09-13 21:51:29 +01:00
PieDuck 34eea827e7 changelog 2026-09-13 21:51:09 +01:00
PieDuck 06c6ee5a9c Merge branch cobblemon:main into typegem-advancement-trigger 2026-09-13 21:37:22 +01:00
PieDuck 54748c20ea Add type gem item advancement trigger 2026-09-13 21:36:18 +01:00
Polymeta 02e63b6fc8 Merge branch 'gem-block-alert' into 'main'
Fixed Missing Recipe Advancements

See merge request cable-mc/cobblemon!2409
2026-09-13 14:41:13 +00:00
Polymeta 3aebcf66ec rename lang file to match convention 2026-09-13 14:26:44 +00:00
dhi_holo 49a5f716b7 Fixed Missing Recipe Advancements
Why were the advancements in the recipes..?
2026-09-13 22:05:44 +10:00
Hiroku 0bd7b4dab3 Merge branch 'decorative-items-restored' into 'main'
Decorative Items Project Returns

See merge request cable-mc/cobblemon!2343
2026-09-13 02:24:00 +00:00
Hiroku 8cbada0cf5 Fix changelog whackiness [skip-ci] 2026-09-13 12:23:40 +10:00
Hiroku f0784fec2d Merge remote-tracking branch 'origin/main' into decorative-items-restored 2026-09-13 12:21:54 +10:00
Hiroku cfe0c5e0a5 Snap on 2026-09-13 11:27:40 +10:00
Hiroku 0bc5bb5caa Snap off and changelog updates 2026-09-13 08:03:56 +10:00
Hiroku 3330941a2c Merge remote-tracking branch 'origin/lang-updates' 2026-09-13 07:58:31 +10:00
Polymeta 79ea082d7e Merge branch '1.8.1-final-engi-fixes' into 'main'
1.8.1 final engi fixes

See merge request cable-mc/cobblemon!2404
2026-09-12 20:09:26 +00:00
Kenji_64 3d78929ff0 Entire Applin line has placeholder anims now! + other Applin related minor fixes 2026-09-12 21:36:12 +02:00
Kenji_64 5d94b03f7a Fixed Lucario's aura particles not emitting 2026-09-12 21:32:48 +02:00
Kenji_64 587305eb52 Added Fickle Beam's double damage text to en_us 2026-09-12 21:28:52 +02:00
Polymeta e363ce5e0e Merge branch 'Log-Spam-Fix' into 'main'
Fixed console spam with carved_ice_spikes. Fixed air pockets in deep sea spires

See merge request cable-mc/cobblemon!2403
2026-09-12 17:14:50 +00:00
Slippy e49b704200 Fixed console spam with carved_ice_spikes. Fixed air pockets in deep sea spires 2026-09-12 11:39:48 -05:00
Polymeta ec8b35860c Merge branch '1.8.1-implementation-fixes' into 'main'
fixed sableye's shoulder mount animations (thanks @kiteman.exe from discord)

See merge request cable-mc/cobblemon!2402
2026-09-12 06:40:07 +00:00
ewwww 74c49bf2da fixed sableye's shoulder mount animations (thanks @kiteman.exe from discord) 2026-09-11 22:39:37 -04:00
Gustavo PuerariandWeblate c03e7d9ed3 Translated using Weblate (Portuguese (Brazil))
Currently translated at 96.8% (9175 of 9472 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2026-09-10 18:30:26 +00:00
Gustavo PuerariandWeblate 2652e53e0c Translated using Weblate (Portuguese (Brazil))
Currently translated at 96.0% (9097 of 9472 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2026-09-10 10:03:46 +00:00
Gustavo PuerariandWeblate b423fb1c46 Translated using Weblate (Portuguese (Brazil))
Currently translated at 95.4% (9040 of 9472 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2026-09-10 00:39:17 +00:00
Gustavo PuerariandWeblate 8ae26a268a Translated using Weblate (Portuguese (Brazil))
Currently translated at 95.1% (9016 of 9472 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2026-09-10 00:11:34 +00:00
Gustavo PuerariandWeblate 39b522abcc Translated using Weblate (Portuguese (Brazil))
Currently translated at 95.0% (9005 of 9472 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2026-09-10 00:05:18 +00:00
Gustavo PuerariandWeblate 9bcfcef4fd Translated using Weblate (Portuguese (Brazil))
Currently translated at 94.8% (8983 of 9472 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2026-09-09 23:29:29 +00:00
Gustavo PuerariandWeblate 60ac2d8058 Translated using Weblate (Portuguese (Brazil))
Currently translated at 94.4% (8947 of 9472 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2026-09-09 23:06:46 +00:00
Gustavo PuerariandWeblate 9366d28141 Translated using Weblate (Portuguese (Brazil))
Currently translated at 94.4% (8946 of 9472 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2026-09-09 22:24:00 +00:00
阿鱼andWeblate 75b48196b7 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (9472 of 9472 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-09-09 14:13:55 +00:00
Paul f6dbb1387c lil bit of doco [skip-ci] 2026-09-08 18:23:00 +10:00
Paul 1a27e14bec Wait that's meant to be withSuffix 2026-09-08 18:17:37 +10:00
dhi_holo 75bc03fdcb Merge branch 'main' into decorative-items-restored 2026-09-07 15:19:27 +10:00
Paul 7915f3f94e Merge branch 'version/1.9' into form_changes
# Conflicts:
#	common/src/main/java/com/cobblemon/mod/common/mixin/ClientPacketListenerMixin.java
#	common/src/main/kotlin/com/cobblemon/mod/common/api/tms/TechnicalMachines.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/block/entity/PokeSnackBlockEntity.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/block/tmmachine/TMMachineMenu.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/gui/summary/Summary.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/RattataAlolanModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/RattataModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/net/messages/client/pokemon/update/evolution/ClientboundSeatAssignmentPacket.kt
#	common/src/main/resources/data/cobblemon/species/generation5/panpour.json
#	common/src/main/resources/data/cobblemon/species/generation8/duraludon.json
2026-09-07 11:46:52 +10:00
Watuneni iteiteandWeblate f65cb9538c Translated using Weblate (Japanese)
Currently translated at 100.0% (9472 of 9472 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-09-06 14:57:47 +00:00
Paul 396ab13164 1.9 in gradle properties 2026-09-06 20:01:10 +10:00
dhi_holo 309ff3da13 Loaded Cleanup
Added Loaded Dice, cleaned up some particles
2026-08-12 20:15:52 +10:00
dhi_holo 3af91e2a74 Further Tweaking 2026-08-12 14:26:20 +10:00
dhi_holo 2e027e3db7 Some Visual and Auditory Tweaks 2026-08-12 14:13:21 +10:00
dhi_holo fc40fb02c0 Next Batch
Never-Melt Ice, Wide, Scope, and Zoom Lens, as well as new designs for Upgrade and Dubious Disc
2026-08-12 13:52:13 +10:00
dhi_holo 2c1c0299f9 SPHERICAL!
Adds Flame Orb, Life Orb, Toxic Orb, Light Ball, and Smoke Ball blocks
2026-08-12 12:24:21 +10:00
dhi_holo 08cbbaf68c Merge branch 'main' into decorative-items-restored 2026-08-10 10:21:06 +10:00
Sterrezo 6e911acf01 Sound tweaks
Swapped pot sound types from tumblestone to decorated pots and rock sounds from tumblestone to deepslate.
2026-08-09 12:20:13 +02:00
dhi_holo f6d82a1b28 Changelog
and some last second sound tweaks
2026-08-09 19:17:19 +10:00
dhi_holo 702126aeab Adds Throat Spray and Iron Ball
Adds in Throat Spray and Iron Ball blocks, finishes clean up of King's Rock to look a bit more consistent
2026-08-09 19:04:08 +10:00
dhi_holo df566e8fcb Wearable Hat Cleanup
Fixed King's Rock Blockstate and loot table as well

Wearable "Hat" Items can now be prevented from swapping when trying to open the interaction wheel (sneak right-click), making it not a nightmare to give certain items to Pokemon. Yippee!
2026-08-09 18:53:58 +10:00
dhi_holo c83e0f33b5 Wearable Items Mostly Working Better
Wearable Items now can either be "Blocks" or "Hats"
"Blocks" can be placed as blocks in the world, while "Hats" can be put on the player's head by right clicking them in hand
Need to add some form of override when crouching and looking at a Pokemon though
2026-08-09 17:30:49 +10:00
dhi_holo f279f936b6 Generified Plaque/Wreath/Magnet Code
Moved shared code to a singular class
2026-08-09 16:04:22 +10:00
dhi_holo f8e20bafd9 Import Cleanup 2026-08-09 12:23:19 +10:00
dhi_holo a5211ca7ff Convention Alignment
Changed all stackable item blockstates/model files to utilise the convention from vanilla (seen on blocks such as pink petals)
This commit adds no files, and removes no files, it purely renames and swaps out numbers
2026-08-09 12:06:01 +10:00
dhi_holo 2f7bedf001 Update scribblenotes - Decorative Items.txt 2026-08-08 18:05:17 +10:00
dhi_holo 44c31a9ddb Update StackableItemBlock.kt
Simplified the way the hitboxes are defined, to allow for future planned hitboxes to actually work as intended
2026-08-08 17:33:34 +10:00
dhi_holo cfc8a15db1 Update scribblenotes - Decorative Items.txt 2026-08-06 18:35:29 +10:00
dhi_holo d5ba22a86c Removal of Unneeded Lines
deprecate deez nuts
2026-08-06 15:01:34 +10:00
dhi_holo a38505f1c5 Update scribblenotes - Decorative Items.txt
Documenting ideas and plans for future me
2026-08-05 19:28:29 +10:00
dhi_holo 3cf1ba1fb3 Tag Tweaks
Added stuff to relevant tags, removed unused tag from removed feature
2026-08-05 18:36:38 +10:00
dhi_holo 9f5d595827 Import Cleanup
Just removing some imports from reverted changes that snuck into commits
2026-08-05 18:03:06 +10:00
dhi_holo 75673f0204 Mild Polish 2026-08-05 17:09:40 +10:00
dhi_holo b43a7571ff Eject Button
Now with cleaner code, I hope this is more acceptable
2026-08-05 16:13:24 +10:00
dhi_holo b071dc04d3 Metronome
Reimplemented the Metronome, the code has been genericized to allow for more items to be implemented off the same base, although a little bit more work does need to be done there with the comparator output specifically
2026-08-05 15:34:32 +10:00
dhi_holo 12f9ff1647 Wreath, Magnet, and some tweaks to Plaques
Plaques now place the way I had originally set them up, and Galarica Wreaths along with the Magnet are back
2026-08-05 14:34:41 +10:00
dhi_holo 3256a302df Ring Target
Could maybe be polished up, but is good
2026-08-05 13:06:07 +10:00
dhi_holo edbe447477 Basic Decorations
Reimplemented Galarica Cuff, Teapots, Teacups, Weather Rocks, Sachet, Metal Powder, Quick Powder, Bright Powder, Destiny Knot, and Luminous Moss
2026-08-05 12:04:48 +10:00
Gertimoshka 2f43910368 Cleaner Implementation with less duplicate code 2026-08-04 22:21:58 +03:00
dhi_holo c2e87e4cfa Placeable Vitamins Experiment A
Need coder feedback regarding this
Makes Mochi and Feathers require clicking in the air or directly on a Pokemon, if it thinks it can place as a block it prevents usage
2026-08-04 19:25:13 +10:00
dhi_holo e40d2ee806 Create scribblenotes - Decorative Items.txt
Making this a unique commit so it's easy to reference back to later
2026-08-04 14:53:53 +10:00
dhi_holo ba74e7603b Wearables 1
Made Sharp Beak, Covert Cloak, and Shell Helmet wearable
2026-08-04 13:51:49 +10:00
dhi_holo 19c3fe6dc4 Update StackableItemBlock.kt
Fixed hitbox oversight
2026-08-04 13:35:17 +10:00
dhi_holo d0778dd124 Missing Stackables 1
Reimplemented Metal Coat, PP Up, and PP Max's placeable logic
Began work for other Vitamins to work (incomplete)
Added models, textures, blockstates, and loot tables for most incoming blocks
2026-08-04 13:16:46 +10:00
Paul e29087c805 Added molang TransformationRequirement 2026-06-12 15:18:51 +10:00
Paul e850253d88 Implemented action-effect driven temporary form reversion and custom Schedulables in action effects 2026-06-12 14:42:14 +10:00
Paul bbb692f521 Moved transformation progress to a common location and reduced the Transformation tree complexity. Progress works for forms 2026-06-12 12:22:15 +10:00
Paul da1d67bbe6 Clean up parentForm mechanism in FormData 2026-06-08 09:01:24 +10:00
Paul 792834f219 Oh yeah compilation should succeed 2026-06-04 18:27:37 +10:00
Paul 94b31cd658 Remove comment 2026-06-04 18:08:52 +10:00
Paul 19364f39c6 Renaming and restructuring of the actual starting of transformations, added FormEvents 2026-06-04 14:45:13 +10:00
Paul 2fc8f6b9df Oi you got a loicense for that television bruv 2026-05-31 22:15:06 +10:00
Paul 9089ff3bbb Why is the species schema JSON malformed 2026-05-31 21:47:02 +10:00
Paul 90f581051c Simplifications and straightening of transformation controller class tree and codecs 2026-05-31 21:43:06 +10:00
Paul 061bdcc478 Action effect improvements for form transition effects, some cleanup of TemporaryForm reverting 2026-05-31 14:52:12 +10:00
Paul 6811394f71 Compilation fixes and merge conflict resolutions 2026-05-30 13:08:20 +10:00
Paul 1235a70323 Conflict resolve maybe 2026-05-26 21:15:00 +10:00
Segfault Guy d94952347f Portrait updates and form effects. 2025-04-30 00:30:06 -04:00
Segfault Guy 7fe6141640 form20 blaze it 2025-04-20 23:41:12 -04:00
Segfault Guy 4b1653ca6c Merge remote-tracking branch 'origin/main' into form_changes 2025-04-20 20:53:54 -04:00
Segfault Guy 7265ab57b9 Apply species schema changes to evolutions. 2025-04-11 01:47:41 -04:00
Segfault Guy 27e3a95b06 cleanup test changes 2025-04-11 01:17:29 -04:00
Segfault Guy 38de3c6267 In-battle form changes and PokemonProperties form completion. 2025-04-09 00:18:10 -04:00
Segfault Guy 376e5ac906 Merge branch 'main' into form_changes 2025-03-18 22:26:00 -04:00
Segfault Guy b225283dcc Toggleable, deferrable, and wild forms. 2025-03-12 23:00:29 -04:00
Segfault Guy b90f852a71 Clear invalid forms on species change. 2025-02-24 20:12:23 -05:00
Segfault Guy fdf7a9703a coalesce temp and perm forms under same property and instead deserialize by custom adapter instead of having unique properties. 2025-02-23 23:21:43 -05:00
Segfault Guy bb41f28342 Merge remote-tracking branch 'origin/main' into form_changes 2025-02-18 22:33:23 -05:00
Segfault Guy c5ee7ebe7a Fix ability registration for forms. 2025-02-11 21:40:35 -05:00
Segfault Guy f6ae10e1d9 It's about f(orm)cking time. 2025-02-03 23:38:53 -05:00
Segfault GuyandSegfault Guy b2070b53fb Changing form... changes form? Wow! 2024-12-03 23:41:17 -05:00
Segfault GuyandSegfault Guy 7fb873dc2c Showdown Form and Species registration rework. 2024-12-03 23:10:25 -05:00
Segfault GuyandSegfault Guy 641f529de3 Better Form and Evolution triggering. 2024-12-03 19:12:41 -05:00
Segfault GuyandSegfault Guy db9fb4fefa Refactor Evolution and add Transformation to expand application of Evolution events and requirements. 2024-12-02 23:13:57 -05:00
2370 changed files with 24130 additions and 52530 deletions
+24 -36
View File
@@ -1,54 +1,40 @@
# Changelog
## [1.8.1 (MONTH Xth, 2026)](#1-8-1)
## [1.8.2 (MONTH xth, 2026)](#1-8-2)
### Additions
- The following items can now be placed on the ground as blocks:
- King's Rock, Galarica Cuff, Unremarkable Teacup, Masterpiece Teacup, Chipped Pot, Cracked Pot, Sachet, Metal Powder, Quick Powder, Bright Powder, Icy Rock, Heat Rock, Smooth Rock, Damp Rock, Destiny Knot, Luminous Moss, Never-Melt Ice, Wide Lens, Scope Lens, and Zoom Lens.
- Iron Ball, Metal Coat, Throat Spray, HP Up, Protein, Iron, Carbos, Calcium, Zinc, PP Up, PP Max, Upgrade, Dubious Disc, and Loaded Dice.
- The following items can now be placed on various surfaces:
- Galarica Wreath, Magnet, Flame Orb, Life Orb, Toxic Orb, Light Ball, and Smoke Ball.
- The following items can now be placed as blocks, and have additional functionality:
- Ring Target, Metronome, and Eject Button.
- The following items can now be worn by Players and Pokémon:
- Galarica Wreath, Cleanse Tag, Spell Tag, Sharp Beak, Covert Cloak, Shell Helmet, and Never-Melt Ice.
- Wearable items can now be equipped by a player by holding it and right-clicking (or rebound use/interact)
- Wearable items that can be placed down are exempt from this behaviour.
### New rideable Pokémon
### Pokémon Added
#### Regional Forms
### Model updates for the following Pokémon
### Animation updates for the following Pokémon
#### Added sounds to the following moves
### Changes
- Updated various recipes to display in Recipe Groups within the Recipe Book
- Updated most recipes to display more logically/consistently within the Recipe Book's categories
### Fixes
- Fixed the `stat_compare` and `stat_equal` evolution requirements crashing the game when given `special_attack` or `special_defence`, and made them treat any non-permanent stat as a failed requirement instead of crashing.
- Fixed the Beast Ball not applying its 0.1× penalty to Pokémon that are not Ultra Beasts.
- Fixed the Moon Ball reading the world's total elapsed time instead of the time of day, so its bonus applied during the day instead.
- Fixed the Love Ball never awarding its 2.5× opposite gender bonus, and matching species by display name instead of identifier.
- Fixed the Timer Ball being weaker than a regular Poké Ball on early turns and only reaching 4× on turn 14 instead of turn 10.
- Fixed the Luxury Ball only doubling Friendship gains of 1, leaving level up and berry gains unaffected.
- Fixed NPCs getting their own TM progress file.
- Fixed the TM Machine refusing move selections that the `unlockAllMoveDexMovesByDefault` config had made visible, leaving the move slot blank and the craft button unresponsive.
- Fixed Rufflet, Braviary, and Hisuian Braviary flooding logs with errors about missing sound events.
- Fixed Pokémon property typos in Pangoro and Dedenne herd spawn files.
- Fixed form typo in Rockruff dusk spawn entry.
- Fixed a potential world gen stall with the Type Gem clusters.
- Fixed Rowap and Jacoba berries not correctly altering Pokémon sizes when used as bait
- Fixed Ampharos' eyes not emitting particles
- Fixed Alolan Raticate's cry not playing
- Fixed unintentional watermelon cosmetic for Hisuian Electrode.
- Fixed Blastoise having an unintentional passenger seat
- Fixed odd NeoForge crash due to a dependency being outdated. It will now flag the dependency for being outdated correctly.
- Fixed form typo in Rockruff-Dusk spawn, preventing it from being able to spawn.
- Fixed a potential world gen stall caused by Type Gem clusters.
- Fixed Rowap and Jacoba berries not correctly altering Pokémon sizes when used as bait.
- Fixed Ampharos' eyes not emitting particles.
- Fixed Alolan Raticate's cry not playing.
- Fixed odd NeoForge crash due to a dependency being outdated. It will now correctly flag the dependency for being outdated.
- Fixed several incorrect light-based spawning conditions for ghosts and bugs.
- Removed unused, placeholder habitat pools.
- Fixed Mantyke, Mantine, and Quaxly getting stuck in a recoil 'expression' during battles due to a having an expression mistakenly assigned as a recoil animation.
- Fixed Pokémon on shoulders not animating if they are visibly holding a held item.
- Fixed Mantyke, Mantine, and Quaxly getting stuck in a recoil 'expression' during battles due to a having an expression mistakenly assigned as a recoil animation.
- Fixed Lycanroc's head movement
- Added head movement to Archaludon
- Fixed Duraludon line not having their sleep animations
- Fixed Diglett line not having their faint animations
- Fixed Kingambit moving its legs while walking
- Correctly grants "They're Minerals!" advancement when planting a type gem
- Type Gem Blocks now have advancements to give you the recipe in the recipe book (the data for the advancements were inside the recipes somehow??)
- Some other recipes without advancements have also been corrected
- Corrected the TM Recipes for Charge Beam and Payday
### Developer
@@ -56,5 +42,7 @@
### Particles
#### New Move Animations
### Localization
- Updated translations for:
+41
View File
@@ -0,0 +1,41 @@
# Changelog
## [1.8.1 (September 13th, 2026)](#1-8-1)
### Animation updates for the following Pokémon
- Flapple, Appletun, Dipplin, Hydrapple (placeholder animations only).
### Fixes
- Fixed a potential world generation stall caused by Type Gem clusters.
- Fixed Pokémon on shoulders not animating if they are visibly holding a held item.
- Fixed NPCs getting their own TM progress file.
- Fixed odd NeoForge crash due to a dependency being outdated. It will now correctly flag the dependency for being outdated.
- Fixed the TM Machine refusing move selections that the `unlockAllMoveDexMovesByDefault` config had made visible, leaving the move slot blank and the craft button unresponsive.
- Fixed the Beast Ball not applying its 0.1× penalty to Pokémon that are not Ultra Beasts.
- Fixed the Moon Ball reading the world's total elapsed time instead of the time of day, so its bonus applied during the day instead.
- Fixed the Love Ball never awarding its 2.5× opposite gender bonus, and matching species by display name instead of identifier.
- Fixed the Timer Ball being weaker than a regular Poké Ball on early turns and only reaching 4× on turn 14 instead of turn 10.
- Fixed the Luxury Ball only doubling Friendship gains of 1, leaving level up and berry gains unaffected.
- Fixed Rufflet, Braviary, and Hisuian Braviary flooding logs with errors about missing sound events.
- Fixed Pokémon property typos in Pangoro and Dedenne herd spawn files.
- Fixed unintentional watermelon cosmetic for Hisuian Electrode.
- Fixed Blastoise having an unintentional passenger seat.
- Fixed form typo in Rockruff-Dusk spawn, preventing it from being able to spawn.
- Fixed the `stat_compare` and `stat_equal` evolution requirements crashing the game when given `special_attack` or `special_defence`, and made them treat any non-permanent stat as a failed requirement instead of crashing.
- Fixed Rowap and Jacoba berries not correctly altering Pokémon sizes when used as bait.
- Fixed Ampharos' eyes not emitting particles.
- Fixed Alolan Raticate's cry not playing.
- Fixed several incorrect light-based spawning conditions for ghosts and bugs.
- Removed unused, placeholder habitat pools.
- Fixed Mantyke, Mantine, and Quaxly getting stuck in a recoil 'expression' during battles due to having an expression assigned as a recoil animation.
- Fixed Lucario's aura particles not emitting.
- Fixed Lycanroc's head movement.
- Added head movement to Archaludon.
- Fixed Duraludon line not having their sleep animations.
- Fixed Diglett line not having their faint animations.
- Fixed Kingambit moving its legs while walking.
### Localization
- Updated translations for:
- Brazilian Portuguese
- Simplified Chinese
- Japanese
+2 -9
View File
@@ -1,9 +1,9 @@
import utilities.isSnapshot
import utilities.version
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import utilities.isSnapshot
import utilities.version
/*
*
@@ -32,7 +32,6 @@ repositories {
maven(url = "https://api.modrinth.com/maven")
maven(url = "https://maven.neoforged.net/releases")
maven(url = "https://maven.gegy.dev")
mavenCentral()
mavenLocal()
}
@@ -41,7 +40,6 @@ dependencies {
modImplementation(libs.fabric.loader)
modApi(libs.molang)
// Integrations
compileOnlyApi(libs.jei.api)
modCompileOnly(libs.bundles.common.integrations.compileOnly) {
@@ -64,19 +62,14 @@ dependencies {
// Unit Testing
testImplementation(libs.bundles.unitTesting)
testImplementation(libs.graal.sdk)
testRuntimeOnly(libs.bundles.graal)
}
tasks.withType<Test> {
useJUnitPlatform()
// Static GL mocks must not load a graphics driver on headless CI.
systemProperty("org.lwjgl.opengl.explicitInit", "true")
testLogging {
setEvents(listOf("failed"))
setExceptionFormat("full")
}
System.getProperty("camera.benchmark")?.let { systemProperty("camera.benchmark", it) }
}
tasks.processResources {
@@ -1,153 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.camera;
import com.cobblemon.mod.common.client.render.camera.CameraFeedHandler;
import com.cobblemon.mod.common.client.util.compat.SodiumCompat;
import com.cobblemon.mod.common.platform.events.ClientChunkEvent;
import com.cobblemon.mod.common.platform.events.PlatformEvents;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.SectionPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.chunk.LevelChunk;
import java.util.ArrayList;
import java.util.function.Consumer;
public final class CameraClientChunkCacheExtension {
private static final Long2ObjectOpenHashMap<LevelChunk> CHUNKS = new Long2ObjectOpenHashMap<>();
private CameraClientChunkCacheExtension() {}
public static boolean shouldKeepChunk(ChunkPos chunkPos) {
int renderDistance = Minecraft.getInstance().options.renderDistance().get();
return CameraChunkVisibilityManager.shouldKeepChunk(chunkPos, renderDistance)
|| CameraFeedHandler.shouldAddChunk(chunkPos, renderDistance);
}
public static void retain(LevelChunk chunk) {
synchronized (CHUNKS) {
CHUNKS.put(chunk.getPos().toLong(), chunk);
}
}
public static LevelChunk take(ClientLevel level, int x, int z) {
synchronized (CHUNKS) {
long position = ChunkPos.asLong(x, z);
LevelChunk chunk = CHUNKS.get(position);
return chunk != null && chunk.getLevel() == level ? CHUNKS.remove(position) : null;
}
}
public static void drop(ClientLevel level, ChunkPos chunkPos) {
LevelChunk chunk = take(level, chunkPos.x, chunkPos.z);
if (chunk != null) {
unload(level, chunk);
}
}
public static LevelChunk getChunk(int x, int z) {
synchronized (CHUNKS) {
return CHUNKS.get(ChunkPos.asLong(x, z));
}
}
public static LevelChunk replaceWithPacketData(ClientLevel level, int x, int z, FriendlyByteBuf packetData, CompoundTag chunkTag, Consumer<ClientboundLevelChunkPacketData.BlockEntityTagOutput> tagOutput) {
if (!Minecraft.getInstance().isSameThread()) {
throw new IllegalStateException("Camera chunk packet applied off the client thread");
}
ChunkPos chunkPos = new ChunkPos(x, z);
LevelChunk chunk = getChunk(x, z);
if (chunk == null || chunk.getLevel() != level) {
chunk = new LevelChunk(level, chunkPos);
}
chunk.replaceWithPacketData(packetData, chunkTag, tagOutput);
retain(chunk);
level.onChunkLoaded(chunkPos);
SodiumCompat.getInstance().notifyChunkAdded(level, x, z);
PlatformEvents.CLIENT_CHUNK_LOAD.postEvents(new ClientChunkEvent.Load(chunk, level));
return chunk;
}
public static void prune(ClientLevel level) {
for (LevelChunk chunk : snapshot()) {
if (chunk.getLevel() == level && !shouldKeepChunk(chunk.getPos())) {
try {
drop(level, chunk.getPos());
} finally {
queueLightRemoval(level, chunk.getPos());
}
}
}
}
public static void clear() {
ArrayList<LevelChunk> removed;
synchronized (CHUNKS) {
removed = new ArrayList<>(CHUNKS.values());
CHUNKS.clear();
}
RuntimeException failure = null;
for (LevelChunk chunk : removed) {
ClientLevel level = (ClientLevel) chunk.getLevel();
try {
try {
unload(level, chunk);
} finally {
queueLightRemoval(level, chunk.getPos());
}
} catch (RuntimeException exception) {
if (failure == null) failure = exception;
else if (failure != exception) failure.addSuppressed(exception);
}
}
if (failure != null) throw failure;
}
public static ArrayList<LevelChunk> snapshot() {
synchronized (CHUNKS) {
return new ArrayList<>(CHUNKS.values());
}
}
private static void queueLightRemoval(ClientLevel level, ChunkPos position) {
level.queueLightUpdate(() -> {
LevelLightEngine lightEngine = level.getLightEngine();
lightEngine.setLightEnabled(position, false);
for (int y = lightEngine.getMinLightSection(); y < lightEngine.getMaxLightSection(); y++) {
SectionPos section = SectionPos.of(position, y);
lightEngine.queueSectionData(LightLayer.BLOCK, section, null);
lightEngine.queueSectionData(LightLayer.SKY, section, null);
}
for (int y = level.getMinSection(); y < level.getMaxSection(); y++) {
lightEngine.updateSectionStatus(SectionPos.of(position, y), true);
}
});
}
public static void unload(ClientLevel level, LevelChunk chunk) {
ChunkPos position = chunk.getPos();
try {
SodiumCompat.getInstance().notifyChunkRemoved(level, position.x, position.z);
} finally {
try {
PlatformEvents.CLIENT_CHUNK_UNLOAD.postEvents(new ClientChunkEvent.Unload(chunk, level));
} finally {
level.unload(chunk);
}
}
}
}
@@ -1,155 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.camera;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import it.unimi.dsi.fastutil.longs.LongSet;
import net.minecraft.client.renderer.chunk.SectionRenderDispatcher;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.world.level.Level;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.UUID;
public final class CameraViewAreaExtension {
private static final Long2ObjectOpenHashMap<SectionRenderDispatcher.RenderSection> SECTIONS = new Long2ObjectOpenHashMap<>();
private static final Map<UUID, LongSet> OWNERS = new HashMap<>();
private static SectionRenderDispatcher sectionRenderDispatcher;
private static final AtomicLong REVISION = new AtomicLong();
private static final AtomicLong GRAPH_REVISION = new AtomicLong();
private static final Set<SectionRenderDispatcher.RenderSection> CAMERA_SECTIONS = Collections.synchronizedSet(Collections.newSetFromMap(new WeakHashMap<>()));
private static int minSectionY;
private static int maxSectionY;
private CameraViewAreaExtension() {
}
public static void allChanged(SectionRenderDispatcher dispatcher, Level level) {
clear();
sectionRenderDispatcher = dispatcher;
minSectionY = level.getMinSection();
maxSectionY = level.getMaxSection();
}
public static SectionRenderDispatcher.RenderSection rawFetch(int cx, int cy, int cz, boolean generateNew) {
if (sectionRenderDispatcher == null || cy < minSectionY || cy >= maxSectionY) {
return null;
}
long sectionPos = SectionPos.asLong(cx, cy, cz);
return generateNew ? provideSection(sectionPos) : SECTIONS.get(sectionPos);
}
public static void setDirty(int cx, int cy, int cz, boolean playerChanged) {
SectionRenderDispatcher.RenderSection section = rawFetch(cx, cy, cz, false);
if (section != null) {
section.setDirty(playerChanged);
}
}
public static void onChunkUnload(int sectionX, int sectionZ) {
REVISION.incrementAndGet();
Collection<SectionRenderDispatcher.RenderSection> removed = new ArrayList<>();
for (int sectionY = minSectionY; sectionY < maxSectionY; sectionY++) {
long sectionPos = SectionPos.asLong(sectionX, sectionY, sectionZ);
SectionRenderDispatcher.RenderSection section = SECTIONS.remove(sectionPos);
if (section != null) {
removed.add(section);
}
}
releaseBuffers(removed);
}
public static void clear() {
REVISION.incrementAndGet();
sectionRenderDispatcher = null;
minSectionY = 0;
maxSectionY = 0;
OWNERS.clear();
Collection<SectionRenderDispatcher.RenderSection> removed = new ArrayList<>(SECTIONS.values());
SECTIONS.clear();
releaseBuffers(removed);
}
public static long revision() {
return REVISION.get();
}
public static long graphRevision() {
return GRAPH_REVISION.get();
}
public static boolean onSectionCompiled(SectionRenderDispatcher.RenderSection section) {
// Late camera uploads must not enter the player's graph after their buffers have been released.
if (!CAMERA_SECTIONS.contains(section)) return false;
GRAPH_REVISION.incrementAndGet();
return true;
}
public static void retainSections(UUID cameraId, Collection<SectionRenderDispatcher.RenderSection> sections) {
LongSet positions = new LongOpenHashSet();
for (SectionRenderDispatcher.RenderSection section : sections) {
positions.add(SectionPos.asLong(section.getOrigin()));
}
LongSet previous = OWNERS.put(cameraId, positions);
releaseUnownedSections(previous);
}
public static void releaseSections(UUID cameraId) {
releaseUnownedSections(OWNERS.remove(cameraId));
}
private static void releaseUnownedSections(LongSet positions) {
if (positions == null) return;
Collection<SectionRenderDispatcher.RenderSection> removed = new ArrayList<>();
for (long position : positions) {
if (OWNERS.values().stream().anyMatch(owner -> owner.contains(position))) continue;
SectionRenderDispatcher.RenderSection section = SECTIONS.remove(position);
if (section != null) removed.add(section);
}
releaseBuffers(removed);
}
private static void releaseBuffers(Collection<SectionRenderDispatcher.RenderSection> sections) {
RuntimeException failure = null;
for (SectionRenderDispatcher.RenderSection section : sections) {
try {
section.releaseBuffers();
} catch (RuntimeException exception) {
if (failure == null) failure = exception;
else if (failure != exception) failure.addSuppressed(exception);
}
}
if (failure != null) throw failure;
}
private static SectionRenderDispatcher.RenderSection provideSection(long sectionPos) {
return SECTIONS.computeIfAbsent(sectionPos, CameraViewAreaExtension::createSection);
}
private static SectionRenderDispatcher.RenderSection createSection(long sectionPos) {
if (sectionRenderDispatcher == null) {
throw new IllegalStateException("SectionRenderDispatcher not initialised");
}
BlockPos origin = SectionPos.of(sectionPos).origin();
SectionRenderDispatcher.RenderSection section = sectionRenderDispatcher.new RenderSection(0, origin.getX(), origin.getY(), origin.getZ());
CAMERA_SECTIONS.add(section);
return section;
}
}
@@ -1,14 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.camera.accessor;
public interface CameraFeedRenderState {
boolean cobblemonRenderHand();
boolean cobblemonRenderBlockOutline();
}
@@ -8,8 +8,6 @@
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.api.cinematic.runtime.CinematicManager;
import net.minecraft.world.damagesource.DamageSource;
import com.cobblemon.mod.common.CobblemonNetwork;
import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.api.orientation.OrientationController;
@@ -134,16 +132,6 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
}
}
@Inject(method = "hurt(Lnet/minecraft/world/damagesource/DamageSource;F)Z", at = @At("HEAD"), cancellable = true)
private void cobblemon$cancelDamageDuringCinematicTakeover(DamageSource source, float amount, CallbackInfoReturnable<Boolean> cir) {
final LivingEntity self = (LivingEntity) (Object) this;
if (self instanceof ServerPlayer serverPlayer) {
if (CinematicManager.INSTANCE.isPlayerUnderImmuneTakeover(serverPlayer.getUUID())) {
cir.setReturnValue(false);
}
}
}
@Inject(method = "decreaseAirSupply", at = @At("HEAD"), cancellable = true)
private void cobblemon$conditionalWaterBreathing(
int currentAir,
@@ -11,12 +11,9 @@ package com.cobblemon.mod.common.mixin.accessor;
import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(Entity.class)
public interface AccessorEntity {
@Invoker("updateFluidOnEyes")
void cobblemonUpdateFluidOnEyes();
@Accessor("eyeHeight")
void standingEyeHeight(float standingEyeHeight);
@@ -1,19 +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.client.Camera;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(Camera.class)
public interface CameraAccessor {
@Accessor("detached")
void setDetached(boolean detached);
}
@@ -1,41 +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.client.multiplayer.ClientChunkCache;
import net.minecraft.world.level.chunk.LevelChunk;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.gen.Invoker;
import java.util.concurrent.atomic.AtomicReferenceArray;
@Mixin(ClientChunkCache.Storage.class)
public interface CameraChunkStorageAccessor {
@Accessor("chunks")
AtomicReferenceArray<LevelChunk> cobblemon$getChunks();
@Accessor("chunkRadius")
int cobblemon$getChunkRadius();
@Accessor("chunkCount")
int cobblemon$getChunkCount();
@Accessor("chunkCount")
void cobblemon$setChunkCount(int count);
@Accessor("viewCenterX")
int cobblemon$getViewCenterX();
@Accessor("viewCenterZ")
int cobblemon$getViewCenterZ();
@Invoker("getIndex")
int cobblemon$getIndex(int x, int z);
}
@@ -10,9 +10,7 @@ package com.cobblemon.mod.common.mixin.accessor;
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;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(RecipeBookComponent.class)
@@ -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.accessor;
import net.minecraft.server.level.ServerEntity;
import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(ServerEntity.class)
public interface ServerEntityEntityAccessor {
@Accessor("entity")
Entity getEntity();
}
@@ -9,13 +9,10 @@
package com.cobblemon.mod.common.mixin.accessor;
import net.minecraft.server.level.ServerEntity;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerPlayerConnection;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.gen.Invoker;
import java.util.List;
import java.util.Set;
@Mixin(targets = "net.minecraft.server.level.ChunkMap$TrackedEntity")
@@ -25,7 +22,4 @@ public interface TrackedEntityAccessor {
@Accessor("serverEntity")
ServerEntity getServerEntity();
@Invoker("updatePlayers")
void cobblemon$updatePlayers(List<ServerPlayer> players);
}
}
@@ -15,11 +15,9 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
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.alchemy.PotionBrewing;
import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.item.crafting.RecipeManager;
@@ -34,6 +32,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List;
import java.util.Optional;
@Mixin(BrewingStandBlockEntity.class)
public class BrewingStandBlockEntityMixin {
@@ -9,17 +9,11 @@
package com.cobblemon.mod.common.mixin.brewing;
import com.cobblemon.mod.common.duck.RecipeAwareSlot;
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.world.Container;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.BrewingStandMenu;
import net.minecraft.world.inventory.ContainerData;
import net.minecraft.world.inventory.Slot;
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;
@@ -13,7 +13,6 @@ 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.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;
@@ -1,47 +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.cinematic;
import com.cobblemon.mod.common.api.cinematic.runtime.CinematicViewerScopedEntity;
import com.cobblemon.mod.common.mixin.accessor.ServerEntityEntityAccessor;
import com.cobblemon.mod.common.mixin.accessor.TrackedEntityAccessor;
import net.minecraft.server.level.ServerEntity;
import net.minecraft.server.level.ServerPlayer;
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.CallbackInfo;
import java.util.Set;
import java.util.UUID;
@Mixin(targets = "net.minecraft.server.level.ChunkMap$TrackedEntity")
public abstract class TrackedEntityMixin {
// Cancellation must also unpair existing viewers, or they keep receiving updates after the scope narrows.
@Inject(method = "updatePlayer", at = @At("HEAD"), cancellable = true)
private void cobblemon$filterViewerScopedEntity(ServerPlayer player, CallbackInfo ci) {
final TrackedEntityAccessor self = (TrackedEntityAccessor) this;
final ServerEntity serverEntity = self.getServerEntity();
if (serverEntity == null) return;
final Entity entity = ((ServerEntityEntityAccessor) serverEntity).getEntity();
if (entity == null) return;
if (entity instanceof CinematicViewerScopedEntity scoped) {
final Set<UUID> allowed = scoped.getCobblemonSceneViewers();
if (allowed != null && !allowed.contains(player.getUUID())) {
if (self.getSeenBy().remove(player.connection)) {
serverEntity.removePairing(player);
}
ci.cancel();
}
}
}
}
@@ -1,36 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.client.camera.CameraClientChunkCacheExtension;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.LevelChunk;
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(ClientPacketListener.class)
public abstract class CameraClientPacketListenerMixin {
@Shadow
private ClientLevel level;
@Inject(method = "queueLightRemoval", at = @At("HEAD"), cancellable = true)
private void cobblemon$keepCameraLight(ClientboundForgetLevelChunkPacket packet, CallbackInfo ci) {
ChunkPos position = packet.pos();
LevelChunk retained = CameraClientChunkCacheExtension.getChunk(position.x, position.z);
if (retained != null && retained.getLevel() == level) {
ci.cancel();
}
}
}
@@ -1,127 +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.camera.CameraClientChunkCacheExtension;
import com.cobblemon.mod.common.client.render.camera.CameraFeedHandler;
import com.cobblemon.mod.common.client.render.camera.CameraViewAreaExtension;
import com.cobblemon.mod.common.client.util.compat.SodiumCompat;
import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.ViewArea;
import net.minecraft.client.renderer.chunk.SectionRenderDispatcher;
import net.minecraft.client.renderer.culling.Frustum;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
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.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(value = LevelRenderer.class, priority = 1100)
public abstract class CameraLevelRendererMixin {
private static final int CINEMATIC_RENDER_DISTANCE_CHUNKS = 32;
private static final float CINEMATIC_FOG_DISTANCE = CINEMATIC_RENDER_DISTANCE_CHUNKS * 16;
@Shadow
private SectionRenderDispatcher sectionRenderDispatcher;
@Shadow
private ClientLevel level;
@WrapWithCondition(method = "setupRender", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ViewArea;repositionCamera(DD)V"))
private boolean cobblemon$shouldRepositionCamera(ViewArea viewArea, double x, double z) {
return !CameraFeedHandler.isCapturing();
}
// Sodium owns its setup pipeline even while vanilla feed sections are substituted.
@Inject(method = "setupRender", at = @At("HEAD"), cancellable = true)
private void cobblemon$onSetupRender(Camera camera, Frustum frustum, boolean hasCapturedFrustum, boolean isSpectator, CallbackInfo ci) {
if (CameraFeedHandler.isCapturing() && !SodiumCompat.getInstance().isActive()) {
CameraFeedHandler.prepareVisibleSections(frustum);
ci.cancel();
}
}
@Inject(method = "setLevel", at = @At("HEAD"))
private void cobblemon$onSetLevel(ClientLevel level, CallbackInfo ci) {
try {
if (this.level != level) {
CameraClientChunkCacheExtension.clear();
}
} finally {
CameraViewAreaExtension.clear();
}
}
@Inject(method = "allChanged", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/SectionOcclusionGraph;waitAndReset(Lnet/minecraft/client/renderer/ViewArea;)V"))
private void cobblemon$onAllChanged(CallbackInfo ci) {
CameraViewAreaExtension.allChanged(sectionRenderDispatcher, level);
}
@Inject(method = "addRecentlyCompiledSection", at = @At("HEAD"), cancellable = true)
private void cobblemon$onSectionCompiled(SectionRenderDispatcher.RenderSection section, CallbackInfo ci) {
if (CameraViewAreaExtension.onSectionCompiled(section)) {
ci.cancel();
}
}
@Inject(method = "isSectionCompiled", at = @At("HEAD"), cancellable = true)
private void cobblemon$onIsSectionCompiled(BlockPos pos, CallbackInfoReturnable<Boolean> cir) {
if (CameraFeedHandler.isCapturing()) {
SectionPos sectionPos = SectionPos.of(pos);
SectionRenderDispatcher.RenderSection section = CameraViewAreaExtension.rawFetch(sectionPos.x(), sectionPos.y(), sectionPos.z(), false);
if (section != null && section.getCompiled() != SectionRenderDispatcher.CompiledSection.UNCOMPILED) {
cir.setReturnValue(true);
}
}
}
@ModifyVariable(method = "renderLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/FogRenderer;setupColor(Lnet/minecraft/client/Camera;FLnet/minecraft/client/multiplayer/ClientLevel;IF)V"), ordinal = 1)
private float cobblemon$modifyFogRenderDistance(float original) {
if (CameraFeedHandler.isCapturing())
return CINEMATIC_FOG_DISTANCE;
return original;
}
// A Marker camera otherwise excludes the local player from vanilla entity rendering.
@WrapOperation(
method = "renderLevel",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;getEntity()Lnet/minecraft/world/entity/Entity;")
)
private Entity cobblemon$getCameraEntityDuringCapture(Camera camera, Operation<Entity> original) {
if (CameraFeedHandler.isCapturing()) {
Entity player = Minecraft.getInstance().player;
if (player != null) return player;
}
return original.call(camera);
}
@WrapOperation(
method = "renderLevel",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;isDetached()Z")
)
private boolean cobblemon$isCameraDetachedDuringCapture(Camera camera, Operation<Boolean> original) {
if (CameraFeedHandler.isCapturing()) {
return true;
}
return original.call(camera);
}
}
@@ -8,12 +8,8 @@
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.api.camera.CameraRotation;
import com.cobblemon.mod.common.api.orientation.OrientationController;
import com.cobblemon.mod.common.api.riding.Rideable;
import com.cobblemon.mod.common.client.MountedPokemonAnimationRenderController;
import com.cobblemon.mod.common.client.camera.ClientCameraController;
import com.cobblemon.mod.common.client.render.camera.CameraFeedHandler;
import com.cobblemon.mod.common.client.render.camera.MountedCameraRenderer;
import com.cobblemon.mod.common.duck.CameraDuck;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
@@ -23,15 +19,11 @@ import net.minecraft.client.Camera;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.phys.Vec3;
import java.util.UUID;
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.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 {
@@ -39,7 +31,6 @@ public abstract class CameraMixin implements CameraDuck {
@Shadow private float eyeHeightOld;
@Shadow private BlockGetter level;
@Shadow private Entity entity;
@Final @Shadow private Quaternionf rotation;
@Final @Shadow private Vector3f forwards;
@Final @Shadow private Vector3f up;
@Final @Shadow private Vector3f left;
@@ -51,7 +42,6 @@ public abstract class CameraMixin implements CameraDuck {
@Override public BlockGetter cobblemon$getLevel() {
return level;
}
@Shadow protected abstract void setRotation(float yRot, float xRot);
@Override public Entity cobblemon$getEntity() {
return entity;
@@ -95,29 +85,4 @@ public abstract class CameraMixin implements CameraDuck {
MountedCameraRenderer.INSTANCE.setSmoothRotation(null);
original.call(instance, x, y, z);
}
// Apply after vanilla third-person and sleeping offsets so authored transforms remain exact.
@Inject(method = "setup", at = @At("RETURN"))
private void cobblemon$applyCinematicTransform(BlockGetter level, Entity entity, boolean detached, boolean thirdPersonReverse, float partialTick, CallbackInfo ci) {
UUID capturedId = CameraFeedHandler.getCurrentlyCapturedCamera();
CameraFeedHandler.FeedContext context = capturedId != null ? CameraFeedHandler.getFeedContext(capturedId) : null;
float roll;
if (context != null) {
setPosition(context.getPosition());
setRotation(context.getYaw(), context.getPitch());
roll = context.getRoll();
} else {
if (!ClientCameraController.shouldUseCinematicCamera()) return;
ClientCameraController.ActiveTransform transform = ClientCameraController.getCameraTransform();
if (transform == null) return;
CameraRotation rotation = transform.getRotation();
setPosition(transform.getPosition());
setRotation(rotation.getYaw(), rotation.getPitch());
roll = transform.getRoll();
}
this.rotation.rotateZ((float) Math.toRadians(roll));
OrientationController.Companion.getFORWARDS().rotate(this.rotation, this.forwards);
OrientationController.Companion.getUP().rotate(this.rotation, this.up);
OrientationController.Companion.getLEFT().rotate(this.rotation, this.left);
}
}
@@ -1,178 +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.camera.CameraClientChunkCacheExtension;
import com.cobblemon.mod.common.mixin.accessor.CameraChunkStorageAccessor;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.minecraft.client.multiplayer.ClientChunkCache;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.status.ChunkStatus;
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;
import java.util.concurrent.atomic.AtomicReferenceArray;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
@Mixin(value = ClientChunkCache.class, priority = 1100)
public abstract class ClientChunkCacheMixin {
@Shadow
volatile ClientChunkCache.Storage storage;
@Shadow
@Final
ClientLevel level;
@Shadow
@Final
private LevelChunk emptyChunk;
@Inject(method = "drop", at = @At("HEAD"), cancellable = true)
private void cobblemon$onDrop(ChunkPos chunkPos, CallbackInfo ci) {
if (CameraClientChunkCacheExtension.shouldKeepChunk(chunkPos)) {
CameraChunkStorageAccessor access = (CameraChunkStorageAccessor) (Object) storage;
int index = access.cobblemon$getIndex(chunkPos.x, chunkPos.z);
LevelChunk chunk = access.cobblemon$getChunks().get(index);
if (chunk != null && chunk.getPos().equals(chunkPos)) {
cobblemon$retain(access, index, chunk);
}
ci.cancel();
} else {
CameraClientChunkCacheExtension.drop(level, chunkPos);
}
}
@Inject(method = "updateViewCenter", at = @At("HEAD"))
private void cobblemon$onViewCenter(int x, int z, CallbackInfo ci) {
CameraChunkStorageAccessor access = (CameraChunkStorageAccessor) (Object) storage;
cobblemon$retainOutsideRange(access, x, z, access.cobblemon$getChunkRadius());
}
@Inject(method = "updateViewRadius", at = @At("HEAD"))
private void cobblemon$onViewRadius(int radius, CallbackInfo ci) {
CameraChunkStorageAccessor access = (CameraChunkStorageAccessor) (Object) storage;
cobblemon$retainOutsideRange(access, access.cobblemon$getViewCenterX(), access.cobblemon$getViewCenterZ(), Math.max(2, radius) + 3);
}
@Inject(method = "updateViewCenter", at = @At("TAIL"))
private void cobblemon$afterViewCenter(int x, int z, CallbackInfo ci) {
cobblemon$promoteCameraChunks((CameraChunkStorageAccessor) (Object) storage);
}
@Inject(method = "updateViewRadius", at = @At("TAIL"))
private void cobblemon$afterViewRadius(int radius, CallbackInfo ci) {
cobblemon$promoteCameraChunks((CameraChunkStorageAccessor) (Object) storage);
}
@Inject(method = "tick", at = @At("HEAD"))
private void cobblemon$onTick(BooleanSupplier hasTimeLeft, boolean tickChunks, CallbackInfo ci) {
CameraClientChunkCacheExtension.prune(level);
}
@Inject(method = "replaceWithPacketData", at = @At("HEAD"), cancellable = true)
private void cobblemon$onReplaceWithPacketData(int x, int z, FriendlyByteBuf buffer, CompoundTag chunkTag, Consumer<ClientboundLevelChunkPacketData.BlockEntityTagOutput> tagOutputConsumer, CallbackInfoReturnable<LevelChunk> cir) {
if (!storage.inRange(x, z)) {
if (CameraClientChunkCacheExtension.shouldKeepChunk(new ChunkPos(x, z))) {
cir.setReturnValue(CameraClientChunkCacheExtension.replaceWithPacketData(level, x, z, buffer, chunkTag, tagOutputConsumer));
}
return;
}
CameraChunkStorageAccessor access = (CameraChunkStorageAccessor) (Object) storage;
int index = access.cobblemon$getIndex(x, z);
LevelChunk previous = access.cobblemon$getChunks().get(index);
if (previous != null && (previous.getPos().x != x || previous.getPos().z != z)
&& CameraClientChunkCacheExtension.shouldKeepChunk(previous.getPos())) {
cobblemon$retain(access, index, previous);
}
}
@WrapOperation(method = "replaceWithPacketData", at = @At(value = "NEW", target = "(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/level/ChunkPos;)Lnet/minecraft/world/level/chunk/LevelChunk;"))
private LevelChunk cobblemon$reuseCameraChunk(Level level, ChunkPos position, Operation<LevelChunk> original) {
LevelChunk retained = CameraClientChunkCacheExtension.take(this.level, position.x, position.z);
return retained != null ? retained : original.call(level, position);
}
@Inject(method = "replaceBiomes", at = @At("HEAD"), cancellable = true)
private void cobblemon$onReplaceBiomes(int x, int z, FriendlyByteBuf buffer, CallbackInfo ci) {
LevelChunk chunk = CameraClientChunkCacheExtension.getChunk(x, z);
if (chunk != null && chunk.getLevel() == level) {
chunk.replaceBiomes(buffer);
ci.cancel();
}
}
@Inject(method = "getChunk(IILnet/minecraft/world/level/chunk/status/ChunkStatus;Z)Lnet/minecraft/world/level/chunk/LevelChunk;", at = @At("RETURN"), cancellable = true)
private void cobblemon$onGetChunk(int x, int z, ChunkStatus chunkStatus, boolean requireChunk, CallbackInfoReturnable<LevelChunk> cir) {
if (cir.getReturnValue() == null || cir.getReturnValue() == emptyChunk) {
LevelChunk chunk = CameraClientChunkCacheExtension.getChunk(x, z);
if (chunk != null && chunk.getLevel() == level) {
cir.setReturnValue(chunk);
}
}
}
@Unique
private void cobblemon$promoteCameraChunks(CameraChunkStorageAccessor access) {
AtomicReferenceArray<LevelChunk> chunks = access.cobblemon$getChunks();
for (LevelChunk chunk : CameraClientChunkCacheExtension.snapshot()) {
ChunkPos position = chunk.getPos();
if (chunk.getLevel() != level
|| Math.abs(position.x - access.cobblemon$getViewCenterX()) > access.cobblemon$getChunkRadius()
|| Math.abs(position.z - access.cobblemon$getViewCenterZ()) > access.cobblemon$getChunkRadius()) continue;
int index = access.cobblemon$getIndex(position.x, position.z);
LevelChunk previous = chunks.get(index);
if (previous != null && CameraClientChunkCacheExtension.shouldKeepChunk(previous.getPos())) {
cobblemon$retain(access, index, previous);
previous = null;
}
CameraClientChunkCacheExtension.take(level, position.x, position.z);
chunks.set(index, chunk);
if (previous == null) {
access.cobblemon$setChunkCount(access.cobblemon$getChunkCount() + 1);
} else {
CameraClientChunkCacheExtension.unload(level, previous);
}
}
}
@Unique
private void cobblemon$retainOutsideRange(CameraChunkStorageAccessor access, int centerX, int centerZ, int radius) {
AtomicReferenceArray<LevelChunk> chunks = access.cobblemon$getChunks();
for (int index = 0; index < chunks.length(); index++) {
LevelChunk chunk = chunks.get(index);
if (chunk == null) continue;
ChunkPos position = chunk.getPos();
if ((Math.abs(position.x - centerX) > radius || Math.abs(position.z - centerZ) > radius)
&& CameraClientChunkCacheExtension.shouldKeepChunk(position)) {
cobblemon$retain(access, index, chunk);
}
}
}
@Unique
private void cobblemon$retain(CameraChunkStorageAccessor access, int index, LevelChunk chunk) {
// Detach before loader unload callbacks: lighting and block entities belong to this same LevelChunk.
if (access.cobblemon$getChunks().compareAndSet(index, chunk, null)) {
access.cobblemon$setChunkCount(access.cobblemon$getChunkCount() - 1);
CameraClientChunkCacheExtension.retain(chunk);
}
}
}
@@ -10,9 +10,7 @@ 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;
@@ -9,142 +9,43 @@
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker;
import com.cobblemon.mod.common.client.camera.GameCamera;
import com.cobblemon.mod.common.client.camera.ClientCameraController;
import com.cobblemon.mod.common.client.cinematic.ClientSceneSessionManager;
import com.cobblemon.mod.common.client.render.camera.accessor.CameraFeedRenderState;
import com.cobblemon.mod.common.client.render.camera.CameraFeedHandler;
import com.cobblemon.mod.common.client.render.camera.compositor.CompositorManager;
import net.minecraft.client.Camera;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.client.DeltaTracker;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.function.Predicate;
import java.util.UUID;
@Mixin(GameRenderer.class)
public abstract class GameRendererMixin implements CameraFeedRenderState {
@Shadow private boolean renderHand;
@Shadow private boolean renderBlockOutline;
@Override public boolean cobblemonRenderHand() { return renderHand; }
@Override public boolean cobblemonRenderBlockOutline() { return renderBlockOutline; }
@Shadow @Final @Mutable
private Camera mainCamera;
public class GameRendererMixin {
@Unique
private Camera cobblemon$playerCamera;
long lastTime = -1;
@Unique
private final GameCamera cobblemon$gameCamera = new GameCamera();
@Unique
private boolean cobblemon$usingCinematic;
@Unique
private long cobblemon$lastTime = -1;
@Inject(method = "render", at = @At("HEAD"))
private void cobblemon$swapCamera(DeltaTracker counter, boolean tick, CallbackInfo ci) {
@Inject(
method = "render",
at = @At(value = "TAIL")
)
public void render(DeltaTracker counter, boolean tick, CallbackInfo ci) {
Minecraft client = Minecraft.getInstance();
if (client.level == null) {
cobblemon$restoreCamera();
return;
}
ClientCameraController.advanceFrame(client.isPaused() ? 0f : counter.getRealtimeDeltaTicks() / 20f);
ClientSceneSessionManager.INSTANCE.getAllSessions().forEach(session -> session.refreshCompositor());
if (ClientCameraController.shouldUseCinematicCamera()) {
if (!cobblemon$usingCinematic) {
cobblemon$playerCamera = mainCamera;
mainCamera = cobblemon$gameCamera;
cobblemon$usingCinematic = true;
}
cobblemon$gameCamera.prepare(client, counter.getGameTimeDeltaPartialTick(tick));
} else if (cobblemon$usingCinematic) {
cobblemon$restoreCamera();
}
}
// WrapOperation allows Iris/Sodium to share this call site; Redirect claims it exclusively.
@WrapOperation(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GameRenderer;renderLevel(Lnet/minecraft/client/DeltaTracker;)V"))
private void cobblemon$skipVanillaRenderLevel(GameRenderer instance, DeltaTracker deltaTracker, Operation<Void> original) {
if (!CompositorManager.isFullscreenActive()) {
original.call(instance, deltaTracker);
}
}
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GameRenderer;tryTakeScreenshotIfNeeded()V"))
private void cobblemon$afterLevelRendering(DeltaTracker deltaTracker, boolean renderLevel, CallbackInfo ci) {
boolean compositorNeedsFeeds = CompositorManager.isFullscreenActive()
|| !CompositorManager.INSTANCE.getRequiredFeeds().isEmpty();
if (compositorNeedsFeeds && CameraFeedHandler.hasFeeds()) {
CameraFeedHandler.captureFeeds(deltaTracker);
}
if (CompositorManager.isFullscreenActive()) {
CompositorManager.INSTANCE.compositeAll();
CompositorManager.renderFullscreen();
}
}
@Inject(method = "pick", at = @At("HEAD"), cancellable = true)
private void cobblemon$preventFramePick(float partialTicks, CallbackInfo ci) {
if (CameraFeedHandler.isCapturing())
ci.cancel();
}
@Inject(method = "getFov", at = @At("HEAD"), cancellable = true)
private void cobblemon$overrideCinematicFov(Camera camera, float partialTicks, boolean useFovSetting, CallbackInfoReturnable<Double> cir) {
UUID capturedId = CameraFeedHandler.getCurrentlyCapturedCamera();
Float fov;
if (capturedId != null) {
CameraFeedHandler.FeedContext context = CameraFeedHandler.getFeedContext(capturedId);
fov = context != null ? context.getFov() : null;
} else {
if (camera != cobblemon$gameCamera || !ClientCameraController.shouldUseCinematicCamera()) return;
fov = ClientCameraController.getPrimaryFovOverride();
}
if (fov != null) {
cir.setReturnValue(fov.doubleValue());
}
}
@Inject(method = "render", at = @At(value = "TAIL"))
private void cobblemon$afterRender(DeltaTracker counter, boolean tick, CallbackInfo ci) {
Minecraft client = Minecraft.getInstance();
long newTime = System.currentTimeMillis();
// Don't play scheduled animations when the game is paused
if (client.isPaused()) {
cobblemon$lastTime = newTime;
lastTime = newTime;
return;
}
if (cobblemon$lastTime != -1) {
float delta = (newTime - cobblemon$lastTime) / 1000F;
ClientTaskTracker.INSTANCE.update(delta);
if (lastTime != -1) {
ClientTaskTracker.INSTANCE.update((newTime - lastTime) / 1000F);
}
cobblemon$lastTime = newTime;
lastTime = newTime;
}
@ModifyArg(
@@ -159,12 +60,4 @@ public abstract class GameRendererMixin implements CameraFeedRenderState {
return (entityX) -> !(entity.getVehicle() == entityX && entityX instanceof PokemonEntity) && original.test(entityX);
}
@Unique
private void cobblemon$restoreCamera() {
if (cobblemon$usingCinematic) {
mainCamera = cobblemon$playerCamera;
cobblemon$playerCamera = null;
cobblemon$usingCinematic = false;
}
}
}
@@ -9,7 +9,6 @@
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.client.camera.ClientCameraController;
import com.cobblemon.mod.common.item.PokedexItem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
@@ -29,11 +28,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public class ItemInHandRendererMixin {
@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, MultiBufferSource multiBufferSource, int j, CallbackInfo ci) {
if (ClientCameraController.shouldUseCinematicCamera()) {
ci.cancel();
return;
}
if (abstractClientPlayer.isUsingItem() && abstractClientPlayer.getUseItem().getItem() instanceof PokedexItem) {
ci.cancel();
}
@@ -8,14 +8,11 @@
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.client.camera.ClientCameraController;
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.CameraType;
import net.minecraft.client.Minecraft;
import net.minecraft.client.model.PlayerModel;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.MultiBufferSource;
@@ -34,34 +31,11 @@ public abstract class PlayerRendererMixin extends LivingEntityRenderer<AbstractC
super(context, model, shadowRadius);
}
@WrapOperation(
method = "render(Lnet/minecraft/client/player/AbstractClientPlayer;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/CameraType;isFirstPerson()Z"
)
)
private boolean cobblemon$allowBodyRenderInCinematic(CameraType instance, Operation<Boolean> original) {
if (ClientCameraController.shouldUseCinematicCamera() && ClientCameraController.shouldRenderPlayerBody()) {
return false;
}
return original.call(instance);
}
@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);
}
@Inject(method = "render(Lnet/minecraft/client/player/AbstractClientPlayer;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", at = @At("HEAD"), cancellable = true)
private void cobblemon$hideCinematicPlayer(AbstractClientPlayer player, float yaw, float partialTick, PoseStack poseStack, MultiBufferSource buffers, int light, CallbackInfo ci) {
if (player != Minecraft.getInstance().player) return;
if (ClientCameraController.shouldUseCinematicCamera() && !ClientCameraController.shouldRenderPlayerBody()) {
ci.cancel();
return;
}
}
@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) {
@@ -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.mixin.client;
import com.cobblemon.mod.common.client.render.RenderAlphaScope;
import net.minecraft.client.renderer.RenderStateShard;
import net.minecraft.client.renderer.RenderType;
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(RenderStateShard.class)
public abstract class RenderStateShardMixin {
@Inject(method = "setupRenderState", at = @At("RETURN"))
private void cobblemon$applyScopedAlpha(CallbackInfo ci) {
if ((Object) this instanceof RenderType) RenderAlphaScope.afterMaterialSetup();
}
@Inject(method = "clearRenderState", at = @At("RETURN"))
private void cobblemon$restoreScopedAlpha(CallbackInfo ci) {
if ((Object) this instanceof RenderType) RenderAlphaScope.afterMaterialClear();
}
}
@@ -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;
import com.cobblemon.mod.common.client.render.camera.CameraViewAreaExtension;
import net.minecraft.client.renderer.ViewArea;
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(ViewArea.class)
public class ViewAreaMixin {
@Inject(method = "setDirty", at = @At("HEAD"))
private void cobblemon$markCinematicDirty(int cx, int cy, int cz, boolean reRenderOnMainThread, CallbackInfo ci) {
CameraViewAreaExtension.setDirty(cx, cy, cz, reRenderOnMainThread);
}
}
@@ -9,8 +9,6 @@
package com.cobblemon.mod.common.mixin.entity;
import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.api.cinematic.runtime.CinematicViewerScopedEntity;
import com.cobblemon.mod.common.api.cinematic.runtime.pathfinding.NativeMotionEntity;
import com.cobblemon.mod.common.duck.RidePassenger;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.pokemon.Pokemon;
@@ -27,8 +25,6 @@ import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
@@ -39,35 +35,11 @@ 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.Set;
import java.util.UUID;
@Mixin(Entity.class)
public abstract class EntityMixin implements CinematicViewerScopedEntity {
@Unique
@Nullable
private Set<UUID> cobblemon$sceneViewers = null;
@Nullable
@Override
public Set<UUID> getCobblemonSceneViewers() {
return cobblemon$sceneViewers;
}
@Override
public void setCobblemonSceneViewers(@Nullable Set<UUID> viewers) {
this.cobblemon$sceneViewers = viewers;
}
public abstract class EntityMixin {
@Shadow @Nullable public abstract Entity getVehicle();
@WrapOperation(method = "move", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/Block;stepOn(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/entity/Entity;)V"))
private void cobblemon$skipSimulatedFootsteps(Block block, Level level, BlockPos pos, BlockState state,
Entity entity, Operation<Void> original) {
if (!(entity instanceof NativeMotionEntity)) original.call(block, level, pos, state, entity);
}
@Inject(method = "updateInWaterStateAndDoWaterCurrentPushing", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/Entity;wasTouchingWater:Z", ordinal = 1), cancellable = true)
public void cobblemon$verifyActuallyTouchingWater(CallbackInfo ci) {
if(this.getVehicle() instanceof PokemonEntity) {
@@ -8,11 +8,6 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.cinematic.registry.SceneBuiltinSources
import com.cobblemon.mod.common.net.serverhandling.editor.EditorPreviewSessionRegistry
import com.cobblemon.mod.common.api.cinematic.runtime.CinematicManager
import com.cobblemon.mod.common.api.molangui.MolangUiService
import com.cobblemon.mod.common.CobblemonBuildDetails.smallCommitHash
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.api.SeasonResolver
@@ -81,8 +76,6 @@ import com.cobblemon.mod.common.battles.BattleSide
import com.cobblemon.mod.common.battles.ShowdownThread
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.battles.stadium.StadiumBattleRegistry
import com.cobblemon.mod.common.battles.stadium.StadiumSpectating
import com.cobblemon.mod.common.block.dispenser.DispenserBehaviorRegistry
import com.cobblemon.mod.common.client.CobblemonPack
import com.cobblemon.mod.common.command.argument.*
@@ -104,10 +97,10 @@ import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.aspects.ALPHA_ASPECT
import com.cobblemon.mod.common.pokemon.aspects.CHARACTERISTIC_RAINBOW_ASPECT
import com.cobblemon.mod.common.pokemon.aspects.COSMETIC_SLOT_ASPECT
import com.cobblemon.mod.common.pokemon.aspects.FORM_ASPECTS
import com.cobblemon.mod.common.pokemon.aspects.GENDER_ASPECT
import com.cobblemon.mod.common.pokemon.aspects.MARK_ASPECT
import com.cobblemon.mod.common.pokemon.aspects.SHINY_ASPECT
import com.cobblemon.mod.common.pokemon.evolution.variants.BlockClickEvolution
import com.cobblemon.mod.common.pokemon.feature.SlowpokeTailRegrowthSpeciesFeature
import com.cobblemon.mod.common.pokemon.feature.SlowpokeTailRegrowthSpeciesFeatureProvider
import com.cobblemon.mod.common.pokemon.feature.TagSeasonResolver
@@ -122,6 +115,7 @@ import com.cobblemon.mod.common.pokemon.properties.NoAIProperty
import com.cobblemon.mod.common.pokemon.properties.UnaspectPropertyType
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
import com.cobblemon.mod.common.pokemon.transformation.triggers.BlockClickTrigger
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
import com.cobblemon.mod.common.util.*
import com.cobblemon.mod.common.world.feature.CobblemonPlacedFeatures
@@ -266,9 +260,6 @@ object Cobblemon {
playerDataManager.onPlayerDisconnect(it.player)
RequestManager.onLogoff(it.player)
serverPlayerStructs.remove(it.player.uuid)
MolangUiService.closeAllForPlayer(it.player.uuid)
CinematicManager.onPlayerDisconnect(it.player.uuid)
EditorPreviewSessionRegistry.onPlayerDisconnect(it.player.uuid)
}
PlatformEvents.PLAYER_DEATH.subscribe {
PCLinkManager.removeLink(it.player.uuid)
@@ -283,13 +274,8 @@ object Cobblemon {
PlatformEvents.RIGHT_CLICK_BLOCK.subscribe { event ->
val player = event.player
val block = player.level().getBlockState(event.pos).block
player.party().forEach { pokemon ->
pokemon.lockedEvolutions
.filterIsInstance<BlockClickEvolution>()
.forEach { evolution ->
evolution.attemptEvolution(pokemon, BlockClickEvolution.BlockInteractionContext(block, player.level()))
}
}
val context = BlockClickTrigger.Context(block, player.level())
player.party().forEach { pokemon -> pokemon.triggerTransformations<BlockClickTrigger>(context) }
}
PlatformEvents.CHANGE_DIMENSION.subscribe {
@@ -311,7 +297,6 @@ object Cobblemon {
HeldItemProvider.register(CobblemonHeldItemManager, Priority.LOWEST)
}
fun sendServerSettingsPacketToPlayer(player: ServerPlayer) {
ServerSettingsPacket(
this.config.preventCompletePartyDeposit,
@@ -334,6 +319,7 @@ object Cobblemon {
SHINY_ASPECT.register()
GENDER_ASPECT.register()
FORM_ASPECTS.register()
COSMETIC_SLOT_ASPECT.register()
CHARACTERISTIC_RAINBOW_ASPECT.register()
ALPHA_ASPECT.register()
@@ -364,8 +350,6 @@ object Cobblemon {
CustomPokemonProperty.register(NoAIProperty)
CustomPokemonProperty.register(HeldItemVisibleProperty)
SceneBuiltinSources.register()
CobblemonEvents.POKEMON_PROPERTY_INITIALISED.emit(Unit)
CallbackHandler.setup()
@@ -462,14 +446,7 @@ object Cobblemon {
)
}
PlatformEvents.SERVER_STOPPING.subscribe {
StadiumSpectating.clear()
// Release temporary actor AI/gravity settings before the final world save.
CinematicManager.clear()
}
PlatformEvents.SERVER_STOPPED.subscribe {
StadiumBattleRegistry.clearDynamic()
MolangUiService.closeAll()
storage.unregisterAll(it.server.registryAccess())
playerDataManager.saveAllStores()
playerDataManager.saveExecutor.shutdown()
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.CobblemonBehaviours.autoPokemonBehaviours
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.ai.CobblemonBehaviour
import com.cobblemon.mod.common.api.ai.config.BehaviourConfig
@@ -19,16 +20,7 @@ import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.BehaviourSyncPacket
import com.cobblemon.mod.common.util.adapters.ActivityAdapter
import com.cobblemon.mod.common.util.adapters.BehaviourConfigAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionOrEntityVariableAdapter
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.MemoryModuleTypeAdapter
import com.cobblemon.mod.common.util.adapters.SensorTypeAdapter
import com.cobblemon.mod.common.util.adapters.TaskConfigAdapter
import com.cobblemon.mod.common.util.adapters.TranslatedTextAdapter
import com.cobblemon.mod.common.util.adapters.*
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.endsWith
import com.google.gson.Gson
@@ -109,10 +109,4 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
"poke_snack",
BlockEntityType.Builder.of(::PokeSnackBlockEntity, CobblemonBlocks.POKE_SNACK, CobblemonBlocks.POKE_CAKE).build(null)
)
@JvmField
val STADIUM_BLOCK: BlockEntityType<StadiumBlockEntity> = this.create(
"stadium_block",
BlockEntityType.Builder.of(::StadiumBlockEntity, CobblemonBlocks.STADIUM_BLOCK).build(null)
)
}
@@ -16,6 +16,8 @@ import com.cobblemon.mod.common.block.MintBlock.MintType
import com.cobblemon.mod.common.block.campfirepot.CampfireBlock
import com.cobblemon.mod.common.block.campfirepot.CampfirePotBlock
import com.cobblemon.mod.common.block.chest.GildedChestBlock
import com.cobblemon.mod.common.block.decor.ActivatableDecorationBlock
import com.cobblemon.mod.common.block.decor.RingTargetBlock
import com.cobblemon.mod.common.block.general.BaleBlock
import com.cobblemon.mod.common.block.general.HorizontalRotationCarpetBlock
import com.cobblemon.mod.common.block.general.HorizontalRotationalBlock
@@ -620,6 +622,88 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val WEAKNESS_POLICY = create("weakness_policy", WallAttachedDirectionalShapeBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.ITEM_BLOCK_PAPER_LARGE_SOUNDS).mapColor(MapColor.NONE).noOcclusion().noCollission(), 14, 12, 1))
@JvmField
val RING_TARGET = create("ring_target", RingTargetBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOD).mapColor(MapColor.NONE).noOcclusion().strength(0.125f)))
@JvmField
val MAGNET = create("magnet", MagnetBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.NONE).noOcclusion().strength(0.075f)))
@JvmField
val GALARICA_WREATH = create("galarica_wreath", GalaricaWreathBlock(BlockBehaviour.Properties.of().sound(SoundType.AZALEA_LEAVES).mapColor(MapColor.NONE).noOcclusion().noCollission()))
@JvmField
val FLAME_ORB = create("flame_orb", OrbBlock(BlockBehaviour.Properties.of().sound(SoundType.GLASS).mapColor(MapColor.NONE).noOcclusion().lightLevel{15}))
@JvmField
val TOXIC_ORB = create("toxic_orb", OrbBlock(BlockBehaviour.Properties.of().sound(SoundType.GLASS).mapColor(MapColor.NONE).noOcclusion()))
@JvmField
val LIFE_ORB = create("life_orb", OrbBlock(BlockBehaviour.Properties.of().sound(SoundType.GLASS).mapColor(MapColor.NONE).noOcclusion().lightLevel{7}))
@JvmField
val LIGHT_BALL = create("light_ball", OrbBlock(BlockBehaviour.Properties.of().sound(SoundType.GLASS).mapColor(MapColor.NONE).noOcclusion().lightLevel{13}))
@JvmField
val SMOKE_BALL = create("smoke_ball", OrbBlock(BlockBehaviour.Properties.of().sound(SoundType.GLASS).mapColor(MapColor.NONE).noOcclusion()))
@JvmField
val KINGS_ROCK = create("kings_rock", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.CENTERED_6x))
@JvmField
val GALARICA_CUFF = create("galarica_cuff", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.AZALEA_LEAVES).mapColor(MapColor.NONE).noCollission().noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.FLATTENED_10x4))
@JvmField
val UNREMARKABLE_TEACUP = create("unremarkable_teacup", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DECORATED_POT).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.TEACUP))
@JvmField
val MASTERPIECE_TEACUP = create("masterpiece_teacup", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DECORATED_POT).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.TEACUP))
@JvmField
val CHIPPED_POT = create("chipped_pot", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DECORATED_POT).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.TEAPOT))
@JvmField
val CRACKED_POT = create("cracked_pot", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DECORATED_POT).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.TEAPOT))
@JvmField
val SACHET = create("sachet", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOL).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.POUCH))
@JvmField
val METAL_POWDER = create("metal_powder", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOL).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.POUCH))
@JvmField
val QUICK_POWDER = create("quick_powder", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOL).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.POUCH))
@JvmField
val BRIGHT_POWDER = create("bright_powder", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOL).mapColor(MapColor.NONE).noOcclusion().lightLevel{3}, DecorativeItemBlock.DecorativeItemBlockType.POUCH))
@JvmField
val NEVER_MELT_ICE = create("never_melt_ice", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.GLASS).mapColor(MapColor.NONE).noOcclusion().friction(0.989F), DecorativeItemBlock.DecorativeItemBlockType.NEVERMELT))
@JvmField
val SCOPE_LENS = create("scope_lens", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.COPPER).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.SCOPE))
@JvmField
val WIDE_LENS = create("wide_lens", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.COPPER).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.WIDE))
@JvmField
val ZOOM_LENS = create("zoom_lens", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.COPPER).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.ZOOM))
@JvmField
val ICY_ROCK = create("icy_rock", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DEEPSLATE).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.FLATTENED_8x4))
@JvmField
val HEAT_ROCK = create("heat_rock", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DEEPSLATE).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.FLATTENED_8x4))
@JvmField
val SMOOTH_ROCK = create("smooth_rock", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DEEPSLATE).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.FLATTENED_8x4))
@JvmField
val DAMP_ROCK = create("damp_rock", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DEEPSLATE).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.FLATTENED_8x6))
@JvmField
val DESTINY_KNOT = create("destiny_knot", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOL).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.KNOT))
@JvmField
val LUMINOUS_MOSS = create("luminous_moss", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.MOSS).mapColor(MapColor.NONE).noOcclusion().lightLevel{5}, DecorativeItemBlock.DecorativeItemBlockType.CENTERED_8x))
@JvmField
val METRONOME = create("metronome", ActivatableDecorationBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.NONE).pushReaction(PushReaction.DESTROY).noOcclusion(), ActivatableDecorationBlock.ActivatableDecorationBlockType.METRONOME))
@JvmField
val EJECT_BUTTON = create("eject_button", EjectButtonBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.NONE).pushReaction(PushReaction.DESTROY).noOcclusion().strength(0.125f), 40))
@JvmField
val LOADED_DICE = create("loaded_dice", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.DICE))
@JvmField
val IRON_BALL = create("iron_ball", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.IRON_BALL))
@JvmField
val METAL_COAT = create("metal_coat", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.METAL_COAT))
@JvmField
val UPGRADE = create("upgrade", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.UPGRADE))
@JvmField
val DUBIOUS_DISC = create("dubious_disc", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.UPGRADE))
@JvmField
val THROAT_SPRAY = create("throat_spray", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.THROAT_SPRAY))
@JvmField
val FULL_HEAL = create("full_heal", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.STATUS_RESTORE))
@JvmField
@@ -670,6 +754,23 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val X_SPEED = create("x_${Stats.SPEED.identifier.path}", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.BATTLE_ITEM))
@JvmField
val HP_UP = create("hp_up", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
@JvmField
val PROTEIN = create("protein", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
@JvmField
val IRON = create("iron", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
@JvmField
val CARBOS = create("carbos", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
@JvmField
val CALCIUM = create("calcium", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
@JvmField
val ZINC = create("zinc", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
@JvmField
val PP_UP = create("pp_up", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
@JvmField
val PP_MAX = create("pp_max", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
@JvmField
val MONITOR = create("monitor", MonitorBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(5.0F, 6.0F).lightLevel { if (it.getValue(MonitorBlock.SCREEN) != MonitorBlock.MonitorScreen.OFF) 13 else 0 }))
@JvmField
@@ -682,12 +783,10 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val HEALING_MACHINE = create("healing_machine", HealingMachineBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).strength(2F).noOcclusion().lightLevel { if (it.getValue(HealingMachineBlock.CHARGE_LEVEL) >= HealingMachineBlock.MAX_CHARGE_LEVEL) 12 else 5 }))
@JvmField
val STADIUM_BLOCK = create("stadium_block", StadiumBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).strength(3.5F, 6.0F).noOcclusion().pushReaction(PushReaction.BLOCK)))
@JvmField
val PC = create("pc", PCBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).strength(2F).noOcclusion().lightLevel { if ((it.getValue(PCBlock.ON) as Boolean) && (it.getValue(PCBlock.PART) == PCBlock.PCPart.TOP)) 13 else 0 }))
@JvmField
val TM_MACHINE = create(
"tm_machine",
TMMachineBlock(
@@ -716,7 +815,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val PASTURE = create("pasture", PastureBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BROWN).sound(SoundType.WOOD).strength(2F).noOcclusion().pushReaction(PushReaction.BLOCK).lightLevel { if ((it.getValue(PastureBlock.ON) as Boolean) && (it.getValue(PastureBlock.PART) == PastureBlock.PasturePart.TOP)) 13 else 0 }))
@JvmField
val RED_MINT = create("red_mint", MintBlock(MintType.RED, BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_RED).noCollission().randomTicks().instabreak().sound(CobblemonSounds.MINT_SOUNDS).pushReaction(PushReaction.DESTROY)))
@JvmField
val BLUE_MINT = create("blue_mint", MintBlock(MintType.BLUE, BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLUE).noCollission().randomTicks().instabreak().sound(CobblemonSounds.MINT_SOUNDS).pushReaction(PushReaction.DESTROY)))
@@ -15,11 +15,7 @@ import net.minecraft.commands.CommandSourceStack
import net.minecraft.commands.Commands
object CobblemonCommands {
fun register(
dispatcher: CommandDispatcher<CommandSourceStack>,
registry: CommandBuildContext,
selection: Commands.CommandSelection
) {
fun register(dispatcher: CommandDispatcher<CommandSourceStack>, registry: CommandBuildContext, selection: Commands.CommandSelection) {
SpawnPokemon.register(dispatcher)
SpawnNPCCommand.register(dispatcher)
GivePokemon.register(dispatcher)
@@ -65,6 +61,7 @@ object CobblemonCommands {
ChangeBoxWallpaperCommand.register(dispatcher)
RunMolangCommand.register(dispatcher)
RunMolangScriptCommand.register(dispatcher)
SpectateBattleCommand.register(dispatcher)
CobblemonConfigCommand.register(dispatcher)
UnlockPCBoxWallpaperCommand.register(dispatcher)
BehaviourEditCommand.register(dispatcher)
@@ -80,8 +77,5 @@ object CobblemonCommands {
// Possibly lock down registration if and only if under dev environment or running in an environment
// with a certain system environment variable set
CobblemonInfoCommand.register(dispatcher)
CinematicCommand.register(dispatcher)
StadiumBattleCommand.register(dispatcher)
MolangUiCommand.register(dispatcher)
}
}
@@ -13,7 +13,6 @@ import com.cobblemon.mod.common.entity.boat.CobblemonBoatEntity
import com.cobblemon.mod.common.entity.boat.CobblemonChestBoatEntity
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity
import com.cobblemon.mod.common.entity.generic.GenericBedrockEntity
import com.cobblemon.mod.common.entity.stadium.StadiumCameraDroneEntity
import com.cobblemon.mod.common.entity.npc.NPCEntity
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
@@ -82,12 +81,6 @@ object CobblemonEntities : PlatformRegistry<Registry<EntityType<*>>, ResourceKey
@JvmField
val GENERIC_BEDROCK_ENTITY_KEY = cobblemonResource("generic_bedrock")
@JvmField
val STADIUM_CAMERA_DRONE: EntityType<StadiumCameraDroneEntity> = this.create(
"stadium_camera_drone",
EntityType.Builder.of(::StadiumCameraDroneEntity, MobCategory.MISC)
.build(cobblemonResource("stadium_camera_drone").toString())
)
@JvmField
val GENERIC_BEDROCK_ENTITY: EntityType<GenericBedrockEntity> = this.create(
GENERIC_BEDROCK_ENTITY_KEY.path,
EntityType.Builder.of({ _, world -> GenericBedrockEntity(world) }, MobCategory.MISC)
@@ -106,4 +99,4 @@ object CobblemonEntities : PlatformRegistry<Registry<EntityType<*>>, ResourceKey
consumer(POKEMON, PokemonEntity.createAttributes())
consumer(NPC, NPCEntity.createAttributes())
}
}
}
@@ -19,7 +19,6 @@ import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
import net.minecraft.server.packs.resources.PreparableReloadListener
import net.minecraft.tags.TagKey
import net.minecraft.world.inventory.MenuType
import net.minecraft.world.level.GameRules
import net.minecraft.world.level.ItemLike
import net.minecraft.world.level.biome.Biome
@@ -38,7 +38,6 @@ import com.cobblemon.mod.common.item.berry.StatusCuringBerryItem
import com.cobblemon.mod.common.item.food.SinisterTeaItem
import com.cobblemon.mod.common.item.interactive.*
import com.cobblemon.mod.common.item.interactive.ability.AbilityChangeItem
import com.cobblemon.mod.common.item.stadium.StadiumPlacementWandItem
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.pokeball.PokeBall
import com.cobblemon.mod.common.pokemon.IVs
@@ -75,9 +74,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val NPC_EDITOR = create("npc_editor", CobblemonItem(Item.Properties().stacksTo(1)))
@JvmField
val STADIUM_PLACEMENT_WAND = create("stadium_placement_wand", StadiumPlacementWandItem())
@JvmField
val pokeBalls = mutableListOf<PokeBallItem>()
@JvmField
@@ -469,8 +465,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
val PASTURE = blockItem("pasture", CobblemonBlocks.PASTURE)
@JvmField
val DISPLAY_CASE = blockItem("display_case", CobblemonBlocks.DISPLAY_CASE)
@JvmField
val STADIUM_BLOCK = blockItem("stadium_block", CobblemonBlocks.STADIUM_BLOCK)
// @JvmField
// val INCENSE_SWEET = blockItem("incense_sweet", CobblemonBlocks.INCENSE_SWEET) // TODO after 1.7
@@ -478,9 +472,9 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
// Evolution items
@JvmField val LINK_CABLE = create("link_cable", LinkCableItem())
@JvmField val DRAGON_SCALE = noSettingsItem("dragon_scale")
@JvmField val METAL_COAT = noSettingsItem("metal_coat")
@JvmField val UPGRADE = noSettingsItem("upgrade")
@JvmField val DUBIOUS_DISC = noSettingsItem("dubious_disc")
@JvmField val METAL_COAT = itemNameBlockItem("metal_coat", CobblemonBlocks.METAL_COAT)
@JvmField val UPGRADE = itemNameBlockItem("upgrade", CobblemonBlocks.UPGRADE)
@JvmField val DUBIOUS_DISC = itemNameBlockItem("dubious_disc", CobblemonBlocks.DUBIOUS_DISC)
@JvmField val DEEP_SEA_SCALE = noSettingsItem("deep_sea_scale")
@JvmField val DEEP_SEA_TOOTH = noSettingsItem("deep_sea_tooth")
@JvmField val ELECTIRIZER = noSettingsItem("electirizer")
@@ -489,7 +483,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField val PROTECTOR = noSettingsItem("protector")
@JvmField val REAPER_CLOTH = noSettingsItem("reaper_cloth")
@JvmField val PRISM_SCALE = noSettingsItem("prism_scale")
@JvmField val SACHET = noSettingsItem("sachet")
@JvmField val SACHET = itemNameBlockItem("sachet", CobblemonBlocks.SACHET)
@JvmField val WHIPPED_DREAM = create("whipped_dream", foodItem(8, 0.3f))
@JvmField val STRAWBERRY_SWEET = create("strawberry_sweet", foodItem(6, 0.125f))
@JvmField val LOVE_SWEET = create("love_sweet", foodItem(6, 0.125f))
@@ -498,22 +492,20 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField val FLOWER_SWEET = create("flower_sweet", foodItem(6, 0.125f))
@JvmField val STAR_SWEET = create("star_sweet", foodItem(6, 0.125f))
@JvmField val RIBBON_SWEET = create("ribbon_sweet", foodItem(6, 0.125f))
@JvmField val CHIPPED_POT = noSettingsItem("chipped_pot")
@JvmField val CRACKED_POT = noSettingsItem("cracked_pot")
@JvmField val MASTERPIECE_TEACUP = noSettingsItem("masterpiece_teacup")
@JvmField val UNREMARKABLE_TEACUP = noSettingsItem("unremarkable_teacup")
@JvmField val CHIPPED_POT = itemNameBlockItem("chipped_pot", CobblemonBlocks.CHIPPED_POT)
@JvmField val CRACKED_POT = itemNameBlockItem("cracked_pot", CobblemonBlocks.CRACKED_POT)
@JvmField val MASTERPIECE_TEACUP = itemNameBlockItem("masterpiece_teacup", CobblemonBlocks.MASTERPIECE_TEACUP)
@JvmField val UNREMARKABLE_TEACUP = itemNameBlockItem("unremarkable_teacup", CobblemonBlocks.UNREMARKABLE_TEACUP)
@JvmField val SWEET_APPLE = compostableItem("sweet_apple", foodItem(4, 0.3f), 0.65f)
@JvmField val TART_APPLE = compostableItem("tart_apple", foodItem(4, 0.3f), 0.65f)
@JvmField val SYRUPY_APPLE = compostableItem("syrupy_apple", foodItem(4, 0.3f), 0.65f)
@JvmField val GALARICA_CUFF = noSettingsItem("galarica_cuff")
@JvmField val GALARICA_WREATH = noSettingsItem("galarica_wreath")
@JvmField val GALARICA_CUFF = itemNameBlockItem("galarica_cuff", CobblemonBlocks.GALARICA_CUFF)
@JvmField val BLACK_AUGURITE = noSettingsItem("black_augurite")
@JvmField val PEAT_BLOCK = noSettingsItem("peat_block")
@JvmField val RAZOR_CLAW = noSettingsItem("razor_claw")
@JvmField val RAZOR_FANG = noSettingsItem("razor_fang")
@JvmField val AUSPICIOUS_ARMOR = heldItem("auspicious_armor")
@JvmField val MALICIOUS_ARMOR = heldItem("malicious_armor")
@JvmField val SHELL_HELMET = heldItem("shell_helmet")
@JvmField val METAL_ALLOY = noSettingsItem("metal_alloy")
@JvmField val SCROLL_OF_DARKNESS = noSettingsItem("scroll_of_darkness")
@JvmField val SCROLL_OF_WATERS = noSettingsItem("scroll_of_waters")
@@ -657,17 +649,17 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val EXPERIENCE_CANDY_XL = candyItem("exp_candy_xl") { _, _ -> CandyItem.DEFAULT_XL_CANDY_YIELD }
@JvmField
val CALCIUM = create("calcium", VitaminItem(Stats.SPECIAL_ATTACK))
val CALCIUM = create("calcium", VitaminItem(Stats.SPECIAL_ATTACK, CobblemonBlocks.CALCIUM))
@JvmField
val CARBOS = create("carbos", VitaminItem(Stats.SPEED))
val CARBOS = create("carbos", VitaminItem(Stats.SPEED, CobblemonBlocks.CARBOS))
@JvmField
val HP_UP = create("hp_up", VitaminItem(Stats.HP))
val HP_UP = create("hp_up", VitaminItem(Stats.HP, CobblemonBlocks.HP_UP))
@JvmField
val IRON = create("iron", VitaminItem(Stats.DEFENCE))
val IRON = create("iron", VitaminItem(Stats.DEFENCE, CobblemonBlocks.IRON))
@JvmField
val PROTEIN = create("protein", VitaminItem(Stats.ATTACK))
val PROTEIN = create("protein", VitaminItem(Stats.ATTACK, CobblemonBlocks.PROTEIN))
@JvmField
val ZINC = create("zinc", VitaminItem(Stats.SPECIAL_DEFENCE))
val ZINC = create("zinc", VitaminItem(Stats.SPECIAL_DEFENCE, CobblemonBlocks.ZINC))
@JvmField
val HEALTH_MOCHI = create("health_mochi", MochiItem(Stats.HP))
@JvmField
@@ -749,9 +741,9 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val MAX_REVIVE = create("max_revive", ReviveItem(max = true))
@JvmField
val PP_UP = create("pp_up", PPUpItem(1))
val PP_UP = create("pp_up", PPUpItem(1, CobblemonBlocks.PP_UP))
@JvmField
val PP_MAX = create("pp_max", PPUpItem(3))
val PP_MAX = create("pp_max", PPUpItem(3, CobblemonBlocks.PP_MAX))
@JvmField
val RED_MINT_SEEDS = mintSeed("red", MintType.RED.getCropBlock())
@@ -928,11 +920,18 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField val CHOICE_SPECS = wearableItem("choice_specs")
@JvmField val EXP_SHARE = wearableItem("exp_share")
@JvmField val FOCUS_BAND = wearableItem("focus_band")
@JvmField val KINGS_ROCK = wearableItem("kings_rock")
@JvmField val KINGS_ROCK = wearableBlockItem("kings_rock", CobblemonBlocks.KINGS_ROCK)
@JvmField val NEVER_MELT_ICE = wearableBlockItem("never_melt_ice", CobblemonBlocks.NEVER_MELT_ICE)
@JvmField val MUSCLE_BAND = wearableItem("muscle_band")
@JvmField val ROCKY_HELMET = wearableItem("rocky_helmet")
@JvmField val SAFETY_GOGGLES = wearableItem("safety_goggles")
@JvmField val WISE_GLASSES = wearableItem("wise_glasses")
@JvmField val SHARP_BEAK = wearableItem("sharp_beak")
@JvmField val COVERT_CLOAK = wearableItem("covert_cloak")
@JvmField val SHELL_HELMET = wearableItem("shell_helmet")
@JvmField val GALARICA_WREATH = wearableBlockItem("galarica_wreath", CobblemonBlocks.GALARICA_WREATH)
@JvmField val CLEANSE_TAG = wearableBlockItem("cleanse_tag", CobblemonBlocks.CLEANSE_TAG)
@JvmField val SPELL_TAG = wearableBlockItem("spell_tag", CobblemonBlocks.SPELL_TAG)
// Held Items
@JvmField
@@ -960,17 +959,13 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val CHOICE_SCARF = heldItem("choice_scarf")
@JvmField
val CLEANSE_TAG = itemNameBlockItem("cleanse_tag", CobblemonBlocks.CLEANSE_TAG)
@JvmField
val CLEAR_AMULET = heldItem("clear_amulet")
@JvmField
val COVERT_CLOAK = heldItem("covert_cloak")
@JvmField
val DESTINY_KNOT = heldItem("destiny_knot")
val DESTINY_KNOT = itemNameBlockItem("destiny_knot", CobblemonBlocks.DESTINY_KNOT)
@JvmField
val DRAGON_FANG = heldItem("dragon_fang")
@JvmField
val EJECT_BUTTON = heldItem("eject_button")
val EJECT_BUTTON = itemNameBlockItem("eject_button", CobblemonBlocks.EJECT_BUTTON)
@JvmField
val EJECT_PACK = heldItem("eject_pack")
@JvmField
@@ -984,7 +979,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val FAIRY_FEATHER = heldItem("fairy_feather")
@JvmField
val FLAME_ORB = heldItem("flame_orb")
val FLAME_ORB = itemNameBlockItem("flame_orb", CobblemonBlocks.FLAME_ORB)
@JvmField
val FLOAT_STONE = heldItem("float_stone")
@JvmField
@@ -998,34 +993,32 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val HEAVY_DUTY_BOOTS = heldItem("heavy_duty_boots")
@JvmField
val IRON_BALL = heldItem("iron_ball")
val IRON_BALL = itemNameBlockItem("iron_ball", CobblemonBlocks.IRON_BALL)
@JvmField
val LAGGING_TAIL = heldItem("lagging_tail")
@JvmField
val LEFTOVERS = compostableHeldItem("leftovers", null, 0.50f)
@JvmField
val LIFE_ORB = heldItem("life_orb")
val LIFE_ORB = itemNameBlockItem("life_orb", CobblemonBlocks.LIFE_ORB)
@JvmField
val LIGHT_BALL = heldItem("light_ball")
val LIGHT_BALL = itemNameBlockItem("light_ball", CobblemonBlocks.LIGHT_BALL)
@JvmField
val LIGHT_CLAY = heldItem("light_clay")
@JvmField
val LOADED_DICE = heldItem("loaded_dice")
val LOADED_DICE = itemNameBlockItem("loaded_dice", CobblemonBlocks.LOADED_DICE)
@JvmField
val LUCKY_EGG = heldItem("lucky_egg")
@JvmField
val LUMINOUS_MOSS = heldItem("luminous_moss")
val LUMINOUS_MOSS = itemNameBlockItem("luminous_moss", CobblemonBlocks.LUMINOUS_MOSS)
@JvmField
val MAGNET = heldItem("magnet")
val MAGNET = itemNameBlockItem("magnet", CobblemonBlocks.MAGNET)
@JvmField
val METRONOME = heldItem("metronome")
val METRONOME = itemNameBlockItem("metronome", CobblemonBlocks.METRONOME)
@JvmField
val MIRACLE_SEED = heldItem("miracle_seed")
@JvmField
val MYSTIC_WATER = heldItem("mystic_water")
@JvmField
val NEVER_MELT_ICE = heldItem("never_melt_ice")
@JvmField
val POISON_BARB = heldItem("poison_barb")
@JvmField
val POWER_ANKLET = heldItem("power_anklet")
@@ -1050,13 +1043,11 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val RED_CARD = heldItem("red_card")
@JvmField
val RING_TARGET = heldItem("ring_target")
val RING_TARGET = itemNameBlockItem("ring_target", CobblemonBlocks.RING_TARGET)
@JvmField
val ROOM_SERVICE = heldItem("room_service")
@JvmField
val SCOPE_LENS = heldItem("scope_lens")
@JvmField
val SHARP_BEAK = heldItem("sharp_beak")
val SCOPE_LENS = itemNameBlockItem("scope_lens", CobblemonBlocks.SCOPE_LENS)
@JvmField
val SHED_SHELL = heldItem("shed_shell")
@JvmField
@@ -1068,9 +1059,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val SOFT_SAND = heldItem("soft_sand")
@JvmField
val SPELL_TAG = itemNameBlockItem("spell_tag", CobblemonBlocks.SPELL_TAG)
@JvmField
val SMOKE_BALL = heldItem("smoke_ball")
val SMOKE_BALL = itemNameBlockItem("smoke_ball", CobblemonBlocks.SMOKE_BALL)
@JvmField
val SOOTHE_BELL = heldItem("soothe_bell")
@JvmField
@@ -1078,9 +1067,9 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val TERRAIN_EXTENDER = heldItem("terrain_extender")
@JvmField
val THROAT_SPRAY = heldItem("throat_spray")
val THROAT_SPRAY = itemNameBlockItem("throat_spray", CobblemonBlocks.THROAT_SPRAY)
@JvmField
val TOXIC_ORB = heldItem("toxic_orb")
val TOXIC_ORB = itemNameBlockItem("toxic_orb", CobblemonBlocks.TOXIC_ORB)
@JvmField
val TWISTED_SPOON = heldItem("twisted_spoon")
@JvmField
@@ -1088,9 +1077,9 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val WEAKNESS_POLICY = itemNameBlockItem("weakness_policy", CobblemonBlocks.WEAKNESS_POLICY)
@JvmField
val WIDE_LENS = heldItem("wide_lens")
val WIDE_LENS = itemNameBlockItem("wide_lens", CobblemonBlocks.WIDE_LENS)
@JvmField
val ZOOM_LENS = heldItem("zoom_lens")
val ZOOM_LENS = itemNameBlockItem("zoom_lens", CobblemonBlocks.ZOOM_LENS)
@JvmField
val MENTAL_HERB = compostableHeldItem("mental_herb", null, 0.85F)
@JvmField
@@ -1102,19 +1091,19 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val WHITE_HERB = compostableHeldItem("white_herb", null, 0.85F)
@JvmField
val BRIGHT_POWDER = heldItem("bright_powder")
val BRIGHT_POWDER = itemNameBlockItem("bright_powder", CobblemonBlocks.BRIGHT_POWDER)
@JvmField
val METAL_POWDER = heldItem("metal_powder")
val METAL_POWDER = itemNameBlockItem("metal_powder", CobblemonBlocks.METAL_POWDER)
@JvmField
val QUICK_POWDER = heldItem("quick_powder")
val QUICK_POWDER = itemNameBlockItem("quick_powder", CobblemonBlocks.QUICK_POWDER)
@JvmField
val DAMP_ROCK = heldItem("damp_rock")
val DAMP_ROCK = itemNameBlockItem("damp_rock", CobblemonBlocks.DAMP_ROCK)
@JvmField
val HEAT_ROCK = heldItem("heat_rock")
val HEAT_ROCK = itemNameBlockItem("heat_rock", CobblemonBlocks.HEAT_ROCK)
@JvmField
val SMOOTH_ROCK = heldItem("smooth_rock")
val SMOOTH_ROCK = itemNameBlockItem("smooth_rock", CobblemonBlocks.SMOOTH_ROCK)
@JvmField
val ICY_ROCK = heldItem("icy_rock")
val ICY_ROCK = itemNameBlockItem("icy_rock", CobblemonBlocks.ICY_ROCK)
// Mulch
@JvmField
@@ -1605,7 +1594,16 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
private fun wearableItem(name: String, heldItemRemappedName: String? = null): CobblemonItem = create(
name,
WearableItem(name).also {
WearableHatItem(name).also {
wearables.add(it)
if (heldItemRemappedName != null) {
CobblemonHeldItemManager.registerRemap(it, heldItemRemappedName)
}
}
)
private fun wearableBlockItem(name: String, block: Block, heldItemRemappedName: String? = null): WearableBlockItem = create(
name,
WearableBlockItem(name, block).also {
wearables.add(it)
if (heldItemRemappedName != null) {
CobblemonHeldItemManager.registerRemap(it, heldItemRemappedName)
@@ -15,12 +15,12 @@ import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.ListCodec
import com.mojang.serialization.codecs.PrimitiveCodec
import java.util.Optional
import java.util.UUID
import net.minecraft.core.BlockPos
import net.minecraft.core.GlobalPos
import net.minecraft.core.UUIDUtil
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import java.util.*
object CobblemonMemories {
val memories = mutableMapOf<String, MemoryModuleType<*>>()
@@ -9,7 +9,6 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.molangui.container.MolangContainerMenu
import com.cobblemon.mod.common.block.campfirepot.CookingPotMenu
import com.cobblemon.mod.common.block.tmmachine.TMMachineMenu
import com.cobblemon.mod.common.platform.PlatformRegistry
@@ -17,17 +16,15 @@ import net.minecraft.core.Registry
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceKey
import net.minecraft.world.flag.FeatureFlags
import net.minecraft.world.inventory.MenuType
object CobblemonMenuType : PlatformRegistry<Registry<MenuType<*>>, ResourceKey<Registry<MenuType<*>>>, MenuType<*>>() {
val COOKING_POT = MenuType.register("cooking_pot_menu", ::CookingPotMenu)
val TM_MACHINE = MenuType.register("tm_machine_menu", ::TMMachineMenu)
val MOLANG_UI = create("molang_ui", MenuType(::MolangContainerMenu, FeatureFlags.DEFAULT_FLAGS))
override val registry: Registry<MenuType<*>>
get() = BuiltInRegistries.MENU
override val resourceKey: ResourceKey<Registry<MenuType<*>>>
get() = Registries.MENU
}
}
@@ -17,20 +17,6 @@ import com.cobblemon.mod.common.client.net.battle.*
import com.cobblemon.mod.common.client.net.callback.move.OpenMoveCallbackHandler
import com.cobblemon.mod.common.client.net.callback.party.OpenPartyCallbackHandler
import com.cobblemon.mod.common.client.net.callback.partymove.OpenPartyMoveCallbackHandler
import com.cobblemon.mod.common.client.net.cinematic.BeatChangeHandler
import com.cobblemon.mod.common.client.net.cinematic.FeedAssignmentHandler
import com.cobblemon.mod.common.client.net.cinematic.FeedTransformHandler
import com.cobblemon.mod.common.client.net.cinematic.SceneEndHandler
import com.cobblemon.mod.common.client.net.cinematic.SceneStartHandler
import com.cobblemon.mod.common.client.net.editor.EditorPreviewAckHandler
import com.cobblemon.mod.common.client.net.editor.EditorPreviewStateHandler
import com.cobblemon.mod.common.client.net.editor.EditorRouteResultHandler
import com.cobblemon.mod.common.net.messages.client.editor.EditorRouteResultS2CPacket
import com.cobblemon.mod.common.net.messages.server.editor.EditorRouteRequestC2SPacket
import com.cobblemon.mod.common.net.serverhandling.editor.EditorRouteRequestHandler
import com.cobblemon.mod.common.net.messages.client.editor.EditorPreviewStateS2CPacket
import com.cobblemon.mod.common.net.messages.server.editor.EditorPreviewControlC2SPacket
import com.cobblemon.mod.common.net.serverhandling.editor.EditorPreviewControlHandler
import com.cobblemon.mod.common.client.net.cooking.ToggleCookingPotLidHandler
import com.cobblemon.mod.common.client.net.data.CobblemonMechanicsSyncHandler
import com.cobblemon.mod.common.client.net.data.DataRegistrySyncPacketHandler
@@ -46,10 +32,6 @@ import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormParticleHandler
import com.cobblemon.mod.common.client.net.gui.ExpGainedDataPacketHandler
import com.cobblemon.mod.common.client.net.gui.InteractPokemonUIPacketHandler
import com.cobblemon.mod.common.client.net.gui.PokedexUIPacketHandler
import com.cobblemon.mod.common.client.net.molangui.MolangUiCloseHandler
import com.cobblemon.mod.common.client.net.molangui.MolangUiCompatibilityRequestHandler
import com.cobblemon.mod.common.client.net.molangui.MolangUiOpenHandler
import com.cobblemon.mod.common.client.net.molangui.MolangUiUpdateHandler
import com.cobblemon.mod.common.client.net.gui.SetActiveTMPacketHandler
import com.cobblemon.mod.common.client.net.gui.SetTMMachineContainerDataPacketHandler
import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
@@ -71,16 +53,6 @@ import com.cobblemon.mod.common.client.net.riding.ClientboundUpdateDriverInputHa
import com.cobblemon.mod.common.client.net.settings.OpenCobblemonConfigEditorHandler
import com.cobblemon.mod.common.client.net.settings.ServerSettingsPacketHandler
import com.cobblemon.mod.common.client.net.sound.UnvalidatedPlaySoundS2CPacketHandler
import com.cobblemon.mod.common.client.net.stadium.OpenStadiumConfigHandler
import com.cobblemon.mod.common.client.net.stadium.StadiumConfigResultHandler
import com.cobblemon.mod.common.client.net.stadium.StadiumSpectateStateHandler
import com.cobblemon.mod.common.net.messages.client.stadium.StadiumSpectateStatePacket
import com.cobblemon.mod.common.net.messages.server.stadium.StadiumSpectatePacket
import com.cobblemon.mod.common.net.serverhandling.stadium.StadiumSpectateHandler
import com.cobblemon.mod.common.client.net.stadium.StadiumCinematicHandler
import com.cobblemon.mod.common.net.messages.client.stadium.StadiumCinematicPacket
import com.cobblemon.mod.common.net.messages.server.stadium.EditStadiumCinematicPacket
import com.cobblemon.mod.common.net.serverhandling.stadium.EditStadiumCinematicHandler
import com.cobblemon.mod.common.client.net.spawn.SpawnExtraDataEntityHandler
import com.cobblemon.mod.common.client.net.starter.StarterUIPacketHandler
import com.cobblemon.mod.common.client.net.storage.RemoveClientPokemonHandler
@@ -100,30 +72,17 @@ import com.cobblemon.mod.common.client.net.trade.TradeProcessStartedHandler
import com.cobblemon.mod.common.client.net.trade.TradeStartedHandler
import com.cobblemon.mod.common.client.net.trade.TradeUpdatedHandler
import com.cobblemon.mod.common.net.PacketRegisterInfo
import com.cobblemon.mod.common.net.serverhandling.stadium.RequestStadiumPlacementWandHandler
import com.cobblemon.mod.common.net.serverhandling.stadium.UpdateStadiumBlockHandler
import com.cobblemon.mod.common.net.messages.client.CalculateSeatPositionsPacket
import com.cobblemon.mod.common.net.messages.client.OpenBehaviourEditorPacket
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
import com.cobblemon.mod.common.net.messages.client.SetClientPlayerDataPacket
import com.cobblemon.mod.common.net.messages.client.animation.PlayPosableAnimationPacket
import com.cobblemon.mod.common.net.messages.client.battle.*
import com.cobblemon.mod.common.net.messages.client.cinematic.BeatChangePacket
import com.cobblemon.mod.common.net.messages.client.cinematic.FeedAssignmentPacket
import com.cobblemon.mod.common.net.messages.client.cinematic.FeedTransformPacket
import com.cobblemon.mod.common.net.messages.client.cinematic.SceneEndPacket
import com.cobblemon.mod.common.net.messages.client.cinematic.SceneStartPacket
import com.cobblemon.mod.common.net.messages.client.editor.EditorPreviewAckS2CPacket
import com.cobblemon.mod.common.net.messages.client.callback.OpenMoveCallbackPacket
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyCallbackPacket
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyMoveCallbackPacket
import com.cobblemon.mod.common.net.messages.client.cooking.SeasoningRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.cooking.ToggleCookingPotLidPacket
import com.cobblemon.mod.common.net.messages.client.data.*
import com.cobblemon.mod.common.net.messages.client.molangui.MolangUiClosePacket
import com.cobblemon.mod.common.net.messages.client.molangui.MolangUiCompatibilityRequestPacket
import com.cobblemon.mod.common.net.messages.client.molangui.MolangUiOpenPacket
import com.cobblemon.mod.common.net.messages.client.molangui.MolangUiUpdatePacket
import com.cobblemon.mod.common.net.messages.client.debug.RequestOpenRidingStatsDebugGUIPacket
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
@@ -148,11 +107,10 @@ import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.Add
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.ClearEvolutionsPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.ClientboundSeatAssignmentPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.RemoveEvolutionPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.form.AddFormPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.form.ClearFormsPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.form.RemoveFormPacket
import com.cobblemon.mod.common.net.messages.client.settings.OpenCobblemonConfigScreenPacket
import com.cobblemon.mod.common.net.messages.client.stadium.OpenStadiumConfigPacket
import com.cobblemon.mod.common.net.messages.client.stadium.StadiumConfigResultPacket
import com.cobblemon.mod.common.net.messages.server.stadium.RequestStadiumPlacementWandPacket
import com.cobblemon.mod.common.net.messages.server.stadium.UpdateStadiumBlockPacket
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
import com.cobblemon.mod.common.net.messages.client.sound.UnvalidatedPlaySoundS2CPacket
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnGenericBedrockPacket
@@ -202,8 +160,6 @@ import com.cobblemon.mod.common.net.messages.server.RequestPlayerInteractionsPac
import com.cobblemon.mod.common.net.messages.server.SelectStarterPacket
import com.cobblemon.mod.common.net.messages.server.SendOutPokemonPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleSelectActionsPacket
import com.cobblemon.mod.common.net.messages.server.battle.StadiumPreviewChoicePacket
import com.cobblemon.mod.common.net.serverhandling.battle.StadiumPreviewChoiceHandler
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamLeavePacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamRequestPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamResponsePacket
@@ -223,15 +179,10 @@ import com.cobblemon.mod.common.net.messages.server.debug.OpenRidingStatsDebugGU
import com.cobblemon.mod.common.net.messages.server.debug.ServerboundUpdateRidingSettingsPacket
import com.cobblemon.mod.common.net.messages.server.debug.ServerboundUpdateRidingStatRangePacket
import com.cobblemon.mod.common.net.messages.server.debug.ServerboundUpdateRidingStatsPacket
import com.cobblemon.mod.common.net.messages.server.editor.EditorPreviewStartC2SPacket
import com.cobblemon.mod.common.net.messages.server.editor.EditorPreviewStopC2SPacket
import com.cobblemon.mod.common.net.messages.server.dialogue.EscapeDialoguePacket
import com.cobblemon.mod.common.net.messages.server.dialogue.InputToDialoguePacket
import com.cobblemon.mod.common.net.messages.server.molangui.MolangUiActionPacket
import com.cobblemon.mod.common.net.messages.server.molangui.MolangUiClosedPacket
import com.cobblemon.mod.common.net.messages.server.habitat.SaveHabitatBlockSettingsPacket
import com.cobblemon.mod.common.net.messages.server.npc.SaveNPCPacket
import com.cobblemon.mod.common.net.messages.server.molangui.MolangUiCompatibilityResponsePacket
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket
import com.cobblemon.mod.common.net.messages.server.pasture.PasturePokemonPacket
import com.cobblemon.mod.common.net.messages.server.pasture.SetPastureConflictPacket
@@ -246,6 +197,8 @@ import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetItemHidden
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetMarkingsPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetNicknamePacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.evolution.AcceptEvolutionPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.form.AcceptFormPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.form.RevertFormPacket
import com.cobblemon.mod.common.net.messages.server.riding.DismountPokemonPacket
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdatePassengerPositionPacket
@@ -263,9 +216,11 @@ import com.cobblemon.mod.common.net.messages.server.trade.ChangeTradeAcceptanceP
import com.cobblemon.mod.common.net.messages.server.trade.OfferTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.PerformTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.UpdateTradeOfferPacket
import com.cobblemon.mod.common.net.serverhandling.AcceptFormHandler
import com.cobblemon.mod.common.net.serverhandling.ChallengeHandler
import com.cobblemon.mod.common.net.serverhandling.ChallengeResponseHandler
import com.cobblemon.mod.common.net.serverhandling.RequestInteractionsHandler
import com.cobblemon.mod.common.net.serverhandling.RevertFormHandler
import com.cobblemon.mod.common.net.serverhandling.battle.BattleSelectActionsHandler
import com.cobblemon.mod.common.net.serverhandling.battle.RemoveSpectatorHandler
import com.cobblemon.mod.common.net.serverhandling.battle.SpectateBattleHandler
@@ -286,16 +241,11 @@ import com.cobblemon.mod.common.net.serverhandling.debug.RequestOpenRidingStatsD
import com.cobblemon.mod.common.net.serverhandling.debug.ServerboundUpdateRidingSettingsHandler
import com.cobblemon.mod.common.net.serverhandling.debug.ServerboundUpdateRidingStatRangeHandler
import com.cobblemon.mod.common.net.serverhandling.debug.ServerboundUpdateRidingStatsHandler
import com.cobblemon.mod.common.net.serverhandling.editor.EditorPreviewStartHandler
import com.cobblemon.mod.common.net.serverhandling.editor.EditorPreviewStopHandler
import com.cobblemon.mod.common.net.serverhandling.dialogue.EscapeDialogueHandler
import com.cobblemon.mod.common.net.serverhandling.dialogue.InputToDialogueHandler
import com.cobblemon.mod.common.net.serverhandling.molangui.MolangUiActionHandler
import com.cobblemon.mod.common.net.serverhandling.molangui.MolangUiClosedHandler
import com.cobblemon.mod.common.net.serverhandling.evolution.AcceptEvolutionHandler
import com.cobblemon.mod.common.net.serverhandling.habitat.SaveHabitatBlockSettingsHandler
import com.cobblemon.mod.common.net.serverhandling.npc.SaveNPCHandler
import com.cobblemon.mod.common.net.serverhandling.molangui.MolangUiCompatibilityResponseHandler
import com.cobblemon.mod.common.net.serverhandling.orientation.ServerboundUpdateOrientationHandler
import com.cobblemon.mod.common.net.serverhandling.pasture.PasturePokemonHandler
import com.cobblemon.mod.common.net.serverhandling.pasture.SetPastureConflictHandler
@@ -444,7 +394,6 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(BattleEndPacket.ID, BattleEndPacket::decode, BattleEndHandler))
list.add(PacketRegisterInfo(BattleInitializePacket.ID, BattleInitializePacket::decode, BattleInitializeHandler))
list.add(PacketRegisterInfo(BattleQueueRequestPacket.ID, BattleQueueRequestPacket::decode, BattleQueueRequestHandler))
list.add(PacketRegisterInfo(StadiumBattleStatePacket.ID, StadiumBattleStatePacket::decode, StadiumBattleStateHandler))
list.add(PacketRegisterInfo(BattleFaintPacket.ID, BattleFaintPacket::decode, BattleFaintHandler))
list.add(PacketRegisterInfo(BattleMakeChoicePacket.ID, BattleMakeChoicePacket::decode, BattleMakeChoiceHandler))
list.add(PacketRegisterInfo(BattleHealthChangePacket.ID, BattleHealthChangePacket::decode, BattleHealthChangeHandler))
@@ -461,37 +410,9 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(BattlePersistentStatusPacket.ID, BattlePersistentStatusPacket::decode, BattlePersistentStatusHandler))
list.add(PacketRegisterInfo(BattleMadeInvalidChoicePacket.ID, BattleMadeInvalidChoicePacket::decode, BattleMadeInvalidChoiceHandler))
list.add(PacketRegisterInfo(BattleMusicPacket.ID, BattleMusicPacket::decode, BattleMusicHandler))
list.add(
PacketRegisterInfo(
BattleChallengeExpiredPacket.ID,
BattleChallengeExpiredPacket::decode,
BattleChallengeExpiredHandler
)
)
list.add(
PacketRegisterInfo(
BattleReplacePokemonPacket.ID,
BattleReplacePokemonPacket::decode,
BattleReplacePokemonHandler
)
)
list.add(
PacketRegisterInfo(
BattleTransformPokemonPacket.ID,
BattleTransformPokemonPacket::decode,
BattleTransformPokemonHandler
)
)
list.add(PacketRegisterInfo(SceneStartPacket.ID, SceneStartPacket::decode, SceneStartHandler))
list.add(PacketRegisterInfo(SceneEndPacket.ID, SceneEndPacket::decode, SceneEndHandler))
list.add(PacketRegisterInfo(FeedTransformPacket.ID, FeedTransformPacket::decode, FeedTransformHandler))
list.add(PacketRegisterInfo(FeedAssignmentPacket.ID, FeedAssignmentPacket::decode, FeedAssignmentHandler))
list.add(PacketRegisterInfo(BeatChangePacket.ID, BeatChangePacket::decode, BeatChangeHandler))
list.add(PacketRegisterInfo(EditorPreviewAckS2CPacket.ID, EditorPreviewAckS2CPacket::decode, EditorPreviewAckHandler))
list.add(PacketRegisterInfo(EditorPreviewStateS2CPacket.ID, EditorPreviewStateS2CPacket::decode, EditorPreviewStateHandler))
list.add(PacketRegisterInfo(EditorRouteResultS2CPacket.ID, EditorRouteResultS2CPacket::decode, EditorRouteResultHandler))
list.add(PacketRegisterInfo(BattleChallengeExpiredPacket.ID, BattleChallengeExpiredPacket::decode, BattleChallengeExpiredHandler))
list.add(PacketRegisterInfo(BattleReplacePokemonPacket.ID, BattleReplacePokemonPacket::decode, BattleReplacePokemonHandler))
list.add(PacketRegisterInfo(BattleTransformPokemonPacket.ID, BattleTransformPokemonPacket::decode, BattleTransformPokemonHandler))
// MultiBattleTeam Packets
list.add(PacketRegisterInfo(TeamRequestNotificationPacket.ID, TeamRequestNotificationPacket::decode, TeamRequestNotificationHandler))
@@ -531,11 +452,6 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(RideSettingsSyncPacket.ID, RideSettingsSyncPacket::decode, RideSettingsSyncHandler))
list.add(PacketRegisterInfo(TechnicalMachineRegistrySyncPacket.ID, TechnicalMachineRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(MolangUiOpenPacket.ID, MolangUiOpenPacket::decode, MolangUiOpenHandler))
list.add(PacketRegisterInfo(MolangUiClosePacket.ID, MolangUiClosePacket::decode, MolangUiCloseHandler))
list.add(PacketRegisterInfo(MolangUiUpdatePacket.ID, MolangUiUpdatePacket::decode, MolangUiUpdateHandler))
list.add(PacketRegisterInfo(MolangUiCompatibilityRequestPacket.ID, MolangUiCompatibilityRequestPacket::decode, MolangUiCompatibilityRequestHandler))
// Effects
list.add(PacketRegisterInfo(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler))
list.add(PacketRegisterInfo(SpawnSnowstormEntityParticlePacket.ID, SpawnSnowstormEntityParticlePacket::decode, SpawnSnowstormEntityParticleHandler))
@@ -565,25 +481,8 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(OpenPasturePacket.ID, OpenPasturePacket::decode, OpenPastureHandler))
list.add(PacketRegisterInfo(ClosePasturePacket.ID, ClosePasturePacket::decode, ClosePastureHandler))
list.add(PacketRegisterInfo(PokemonPasturedPacket.ID, PokemonPasturedPacket::decode, PokemonPasturedHandler))
list.add(
PacketRegisterInfo(
PokemonUnpasturedPacket.ID,
PokemonUnpasturedPacket::decode,
PokemonUnpasturedHandler
)
)
list.add(
PacketRegisterInfo(
UpdatePastureConflictFlagPacket.ID,
UpdatePastureConflictFlagPacket::decode,
UpdatePastureConflictFlagHandler
)
)
list.add(PacketRegisterInfo(OpenStadiumConfigPacket.ID, OpenStadiumConfigPacket::decode, OpenStadiumConfigHandler))
list.add(PacketRegisterInfo(StadiumConfigResultPacket.ID, StadiumConfigResultPacket::decode, StadiumConfigResultHandler))
list.add(PacketRegisterInfo(StadiumSpectateStatePacket.ID, StadiumSpectateStatePacket::decode, StadiumSpectateStateHandler))
list.add(PacketRegisterInfo(StadiumCinematicPacket.ID, StadiumCinematicPacket::decode, StadiumCinematicHandler))
list.add(PacketRegisterInfo(PokemonUnpasturedPacket.ID, PokemonUnpasturedPacket::decode, PokemonUnpasturedHandler))
list.add(PacketRegisterInfo(UpdatePastureConflictFlagPacket.ID, UpdatePastureConflictFlagPacket::decode, UpdatePastureConflictFlagHandler))
// Orientation
list.add(PacketRegisterInfo(ClientboundUpdateOrientationPacket.ID, ClientboundUpdateOrientationPacket::decode, ClientboundUpdateOrientationHandler))
@@ -614,6 +513,11 @@ object CobblemonNetwork {
// Pokédex scanning
list.add(PacketRegisterInfo(ServerConfirmedRegisterPacket.ID, ServerConfirmedRegisterPacket::decode, ServerConfirmedRegisterHandler))
// Form packets
list.add(PacketRegisterInfo(AddFormPacket.ID, AddFormPacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(ClearFormsPacket.ID, ClearFormsPacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(RemoveFormPacket.ID, RemoveFormPacket::decode, PokemonUpdatePacketHandler()))
// Riding
list.add(PacketRegisterInfo(ClientboundUpdateRidingStatePacket.ID, ClientboundUpdateRidingStatePacket::decode, ClientboundUpdateRidingStateHandler))
list.add(PacketRegisterInfo(ClientboundUpdateDriverInputPacket.ID, ClientboundUpdateDriverInputPacket::decode, ClientboundUpdateDriverInputHandler))
@@ -681,7 +585,6 @@ object CobblemonNetwork {
// Battle packets
list.add(PacketRegisterInfo(BattleSelectActionsPacket.ID, BattleSelectActionsPacket::decode, BattleSelectActionsHandler))
list.add(PacketRegisterInfo(StadiumPreviewChoicePacket.ID, StadiumPreviewChoicePacket::decode, StadiumPreviewChoiceHandler))
list.add(PacketRegisterInfo(SpectateBattlePacket.ID, SpectateBattlePacket::decode, SpectateBattleHandler))
list.add(PacketRegisterInfo(RemoveSpectatorPacket.ID, RemoveSpectatorPacket::decode, RemoveSpectatorHandler))
@@ -730,6 +633,10 @@ object CobblemonNetwork {
// NPC packets
list.add(PacketRegisterInfo(SaveNPCPacket.ID, SaveNPCPacket::decode, SaveNPCHandler))
// Form Packets
list.add(PacketRegisterInfo(AcceptFormPacket.ID, AcceptFormPacket::decode, AcceptFormHandler))
list.add(PacketRegisterInfo(RevertFormPacket.ID, RevertFormPacket::decode, RevertFormHandler))
// Riding packet(s)
list.add(PacketRegisterInfo(ServerboundUpdateOrientationPacket.ID, ServerboundUpdateOrientationPacket::decode, ServerboundUpdateOrientationHandler))
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatePacket.ID, ServerboundUpdateRidingStatePacket::decode, ServerboundUpdateRidingStateHandler))
@@ -749,29 +656,8 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(SetTMMachineContainerDataPacket.ID, SetTMMachineContainerDataPacket::decode, SetTMMachineContainerDataPacketHandler))
// Behaviour Packets
list.add(
PacketRegisterInfo(
SetEntityBehaviourPacket.ID,
SetEntityBehaviourPacket::decode,
SetEntityBehaviourHandler
)
)
list.add(
PacketRegisterInfo(
DamageOnCollisionPacket.ID,
DamageOnCollisionPacket::decode,
DamageOnCollisionPacketHandler
)
)
list.add(PacketRegisterInfo(UpdateStadiumBlockPacket.ID, UpdateStadiumBlockPacket::decode, UpdateStadiumBlockHandler))
list.add(PacketRegisterInfo(EditStadiumCinematicPacket.ID, EditStadiumCinematicPacket::decode, EditStadiumCinematicHandler))
list.add(PacketRegisterInfo(RequestStadiumPlacementWandPacket.ID, RequestStadiumPlacementWandPacket::decode, RequestStadiumPlacementWandHandler))
list.add(PacketRegisterInfo(StadiumSpectatePacket.ID, StadiumSpectatePacket::decode, StadiumSpectateHandler))
list.add(PacketRegisterInfo(MolangUiActionPacket.ID, MolangUiActionPacket::decode, MolangUiActionHandler))
list.add(PacketRegisterInfo(MolangUiClosedPacket.ID, MolangUiClosedPacket::decode, MolangUiClosedHandler))
list.add(PacketRegisterInfo(MolangUiCompatibilityResponsePacket.ID, MolangUiCompatibilityResponsePacket::decode, MolangUiCompatibilityResponseHandler))
list.add(PacketRegisterInfo(SetEntityBehaviourPacket.ID, SetEntityBehaviourPacket::decode, SetEntityBehaviourHandler))
list.add(PacketRegisterInfo(DamageOnCollisionPacket.ID, DamageOnCollisionPacket::decode, DamageOnCollisionPacketHandler))
// Habitat blocks
list.add(PacketRegisterInfo(SaveHabitatBlockSettingsPacket.ID, SaveHabitatBlockSettingsPacket::decode, SaveHabitatBlockSettingsHandler))
@@ -779,10 +665,6 @@ object CobblemonNetwork {
// Debug / cheats
list.add(PacketRegisterInfo(RequestOpenRidingStatsDebugGUIPacket.ID, RequestOpenRidingStatsDebugGUIPacket::decode, RequestOpenRidingStatsDebugGUIHandler))
list.add(PacketRegisterInfo(EditorPreviewStartC2SPacket.ID, EditorPreviewStartC2SPacket::decode, EditorPreviewStartHandler))
list.add(PacketRegisterInfo(EditorRouteRequestC2SPacket.ID, EditorRouteRequestC2SPacket::decode, EditorRouteRequestHandler))
list.add(PacketRegisterInfo(EditorPreviewStopC2SPacket.ID, EditorPreviewStopC2SPacket::decode, EditorPreviewStopHandler))
list.add(PacketRegisterInfo(EditorPreviewControlC2SPacket.ID, EditorPreviewControlC2SPacket::decode, EditorPreviewControlHandler))
return list
}
@@ -790,4 +672,4 @@ object CobblemonNetwork {
fun sendPacketToPlayer(player: ServerPlayer, packet: NetworkPacket<*>) {
Cobblemon.implementation.networkManager.sendPacketToPlayer(player, packet)
}
}
}
@@ -9,9 +9,9 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.*
import com.cobblemon.mod.common.pokemon.ai.PokemonDisturbancesSensor
import com.cobblemon.mod.common.entity.sensor.BattlingPokemonSensor
import com.cobblemon.mod.common.entity.sensor.NPCBattlingSensor
import com.cobblemon.mod.common.pokemon.ai.PokemonDisturbancesSensor
import java.util.function.Supplier
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.ai.sensing.Sensor
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common
import java.util.Optional
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.util.RandomSource
import net.minecraft.world.entity.Entity
@@ -18,7 +19,6 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraft.world.item.trading.ItemCost
import net.minecraft.world.item.trading.MerchantOffer
import java.util.Optional
/**
* A generator for various trade offers in the mod.
@@ -11,10 +11,10 @@ package com.cobblemon.mod.common.advancement.criterion
import com.cobblemon.mod.common.util.cobblemonResource
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import java.util.Optional
import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import java.util.Optional
class AspectCriterion(
playerCtx: Optional<ContextAwarePredicate>,
@@ -14,8 +14,8 @@ import com.mojang.serialization.codecs.RecordCodecBuilder
import java.util.Optional
import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.advancements.critereon.EntityPredicate
import net.minecraft.server.level.ServerPlayer
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
class CastPokeRodContext(val baitId: ResourceLocation)
@@ -10,10 +10,10 @@ package com.cobblemon.mod.common.advancement.criterion
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import java.util.Optional
import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.advancements.critereon.EntityPredicate
import net.minecraft.server.level.ServerPlayer
import java.util.Optional
/**
* A context that is used when you require a [CountableContext] along with some type string.
@@ -14,8 +14,8 @@ import com.mojang.serialization.codecs.RecordCodecBuilder
import java.util.Optional
import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.advancements.critereon.EntityPredicate
import net.minecraft.server.level.ServerPlayer
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
class ReelInPokemonContext(val species : ResourceLocation, val baitId: ResourceLocation)
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.api.abilities
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
import com.cobblemon.mod.common.util.codec.CodecUtils
import com.google.gson.JsonObject
import com.mojang.serialization.Codec
@@ -25,7 +26,7 @@ class AbilityTemplate(
var builder: (AbilityTemplate, forced: Boolean, priority: Priority) -> Ability = { template, forced, priority -> Ability(template, forced, priority) },
val displayName: String = "cobblemon.ability.$name",
val description: String = "cobblemon.ability.$name.desc"
) {
) : ShowdownIdentifiable {
/**
* Returns the Ability or if applicable the extension connected to this template
*/
@@ -45,6 +46,8 @@ class AbilityTemplate(
*/
fun create(json: JsonObject) = create().loadFromJSON(json)
override fun showdownId(): String = ShowdownIdentifiable.REGEX.replace(this.name.lowercase(), "")
companion object {
@JvmStatic
@@ -18,7 +18,6 @@ import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.molang.ObjectValue
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
import com.cobblemon.mod.common.util.activityRegistry
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
@@ -13,7 +13,6 @@ import com.cobblemon.mod.common.api.ai.config.BehaviourConfig
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
import com.cobblemon.mod.common.util.asTranslated
import com.cobblemon.mod.common.util.resolve
import com.cobblemon.mod.common.util.withQueryValue
@@ -13,7 +13,6 @@ import com.cobblemon.mod.common.util.getBooleanOrNull
import com.cobblemon.mod.common.util.getDoubleOrNull
import kotlin.math.sqrt
import net.minecraft.core.BlockPos
import net.minecraft.world.entity.PathfinderMob
/**
* Used to maintain some settings around how the entity should wander this tick. The idea is you
@@ -8,16 +8,12 @@
package com.cobblemon.mod.common.api.ai.config
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.LivingEntity
@@ -11,13 +11,8 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.weightedSelection
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
@@ -8,12 +8,10 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask.Companion.wrapped
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.util.mainThreadRuntime
import com.cobblemon.mod.common.util.resolveBoolean
@@ -10,8 +10,6 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.StopBeingAngryIfTargetDead
@@ -9,9 +9,7 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.Difficulty
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
@@ -15,7 +15,6 @@ import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.npc.ai.SwitchToBattleTask
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class SwitchToNPCBattleTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = emptyList<MoLangConfigVariable>()
@@ -10,8 +10,6 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.ai.behavior.BehaviorControl
@@ -10,8 +10,6 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.ai.behavior.BehaviorControl
@@ -25,7 +25,6 @@ import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.memory.MemoryStatus
import net.minecraft.world.entity.ai.sensing.SensorType
/**
@@ -22,6 +22,7 @@ import com.cobblemon.mod.common.util.mainThreadRuntime
import com.cobblemon.mod.common.util.resolveFloat
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import kotlin.math.ceil
import net.minecraft.core.BlockPos
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
@@ -34,7 +35,6 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.level.material.Fluids
import net.minecraft.world.level.pathfinder.PathType
import net.minecraft.world.phys.Vec3
import kotlin.math.ceil
class WaterWanderTaskConfig : SingleTaskConfig {
val condition = booleanVariable(WANDER, "water_wanders", true).asExpressible()
@@ -35,7 +35,6 @@ import com.cobblemon.mod.common.battles.ActiveBattlePokemon
import com.cobblemon.mod.common.battles.BattleCaptureAction
import com.cobblemon.mod.common.battles.BattleFormat
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.battles.stadium.StadiumBattleSession
import com.cobblemon.mod.common.battles.BattleSide
import com.cobblemon.mod.common.battles.FleeAttemptActionResponse
import com.cobblemon.mod.common.battles.ForfeitActionResponse
@@ -55,9 +54,9 @@ import com.cobblemon.mod.common.net.messages.client.battle.BattleEndPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMakeChoicePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMessagePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleQueueRequestPacket
import com.cobblemon.mod.common.pokemon.evolution.progress.DefeatEvolutionProgress
import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHitsEvolutionProgress
import com.cobblemon.mod.common.pokemon.requirements.DefeatRequirement
import com.cobblemon.mod.common.pokemon.transformation.progress.DefeatTransformationProgress
import com.cobblemon.mod.common.pokemon.transformation.progress.LastBattleCriticalHitsTransformationProgress
import com.cobblemon.mod.common.pokemon.transformation.requirements.DefeatRequirement
import com.cobblemon.mod.common.util.battleLang
import com.cobblemon.mod.common.util.getPlayer
import com.cobblemon.mod.common.util.giveOrDropItemStack
@@ -81,18 +80,14 @@ import net.minecraft.world.item.ItemStack
open class PokemonBattle(
val format: BattleFormat,
val side1: BattleSide,
val side2: BattleSide,
initializeProgress: Boolean = true
val side2: BattleSide
) {
/** Whether logging will be silenced for this battle. */
var mute = !CobblemonBuildDetails.SNAPSHOT
val struct = this.asMoLangValue()
val runtime = MoLangRuntime().also {
it.environment.query = struct
}
val runtime = MoLangRuntime().also { it.environment.query = struct }
val onEndHandlers: MutableList<(PokemonBattle) -> Unit> = mutableListOf()
var stadiumSession: StadiumBattleSession? = null
val battlePartyStores = mutableListOf<PlayerPartyStore>()
@@ -101,15 +96,9 @@ open class PokemonBattle(
side2.battle = this
this.actors.forEach { actor ->
actor.battle = this
}
if (initializeProgress) resetEvolutionProgress()
}
internal fun resetEvolutionProgress() {
actors.forEach { actor ->
actor.pokemonList.forEach { battlePokemon ->
battlePokemon.effectedPokemon.evolutionProxy.current().progress()
.filterIsInstance<LastBattleCriticalHitsEvolutionProgress>()
battlePokemon.effectedPokemon.requirementProgress
.filterIsInstance<LastBattleCriticalHitsTransformationProgress>()
.forEach { it.reset() }
}
}
@@ -248,9 +237,7 @@ open class PokemonBattle(
}
fun turn(newTurnNumber: Int) {
// Prepare all actors before notifying synchronous AI, or its first response can clear other actors' requests.
actors.forEach { it.prepareTurn() }
actors.forEach { it.fireChoiceRequest() }
actors.forEach { it.turn() }
// TODO: If a pokemon switches in the same turn another pokemon is KO'd it will not receive exp for the KO
for (side in sides) {
val opposite = side.getOppositeSide()
@@ -263,7 +250,6 @@ open class PokemonBattle(
}
fun end() {
if (ended) return
ended = true
val awardToFainted = Cobblemon.config.awardExperienceToFaintedPokemon
val awardOnLoss = Cobblemon.config.awardExperienceOnBattleLoss
@@ -285,12 +271,13 @@ open class PokemonBattle(
val facedFainted = opponentPokemon.facedOpponents.contains(faintedPokemon)
val pokemon = opponentPokemon.effectedPokemon
if (facedFainted) {
pokemon.lockedEvolutions.forEach { evolution ->
evolution.requirements.filterIsInstance<DefeatRequirement>().forEach { defeatRequirement ->
if (defeatRequirement.target.matches(faintedPokemon.effectedPokemon)) {
val progress = pokemon.evolutionProxy.current().progressFirstOrCreate({ it is DefeatEvolutionProgress && it.currentProgress().target == defeatRequirement.target }) { DefeatEvolutionProgress() }
progress.updateProgress(DefeatEvolutionProgress.Progress(defeatRequirement.target, progress.currentProgress().amount + 1))
}
if (pokemon.hasMatchingRequirement<DefeatRequirement>({ it.target.matches(faintedPokemon.effectedPokemon) })) {
val requiredPokemonProperties = pokemon.getRelevantRequirements<DefeatRequirement> { it.target.matches(faintedPokemon.effectedPokemon) }
.map { it.target }
.distinctBy { it.asString() }
for (props in requiredPokemonProperties) {
val progress = pokemon.progressFirstOrCreate({ it is DefeatTransformationProgress && it.currentProgress().target.asString().equals(props.asString(), ignoreCase = true) }, ::DefeatTransformationProgress)
progress.updateProgress(DefeatTransformationProgress.Progress(props.copy(), progress.currentProgress().amount + 1))
}
}
}
@@ -478,7 +465,7 @@ open class PokemonBattle(
val message = battleLang("crash").red()
this.actors.filterIsInstance<PlayerBattleActor>().forEach { it.entity?.sendSystemMessage(message) }
this.saveBattleLog()
if (stadiumSession != null) BattleRegistry.abortStadiumBattle(battleId) else this.stop()
this.stop()
return
}
@@ -486,7 +473,6 @@ open class PokemonBattle(
ticks++
if (isPvW && !ended && dispatches.isEmpty()) checkFlee()
}
stadiumSession?.tick()
}
open fun checkFlee() {
@@ -522,7 +508,6 @@ open class PokemonBattle(
}
fun stop() {
if (ended) return
writeShowdownAction(">forcetie") // This will terminate the Showdown connection
end()
}
@@ -599,4 +584,4 @@ open class PokemonBattle(
queryStruct.addFunction("has_rule") { params -> DoubleValue(params.getString(0) in format.ruleSet) }
return queryStruct
}
}
}
@@ -11,9 +11,8 @@ package com.cobblemon.mod.common.api.battles.model.actor
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.api.battles.model.ai.BattleAI
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.battles.DefaultActionResponse
import com.cobblemon.mod.common.battles.ForcePassActionResponse
import com.cobblemon.mod.common.battles.PassActionResponse
import com.cobblemon.mod.common.battles.ShowdownActionResponse
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.exception.IllegalActionChoiceException
import com.cobblemon.mod.common.net.messages.client.battle.BattleFaintPacket
@@ -50,40 +49,36 @@ abstract class AIBattleActor(
* Called when the AI is requested to make a choice.
*/
open fun onChoiceRequested() {
val req = request
if (req == null) {
responses.clear()
expectingPassActions.clear()
mustChoose = false
battle.checkForInputDispatch()
return
}
val passActions = expectingPassActions.toList()
try {
setActionResponses(req.iterate(this.activePokemon) { battleMon, moveset, forceSwitch ->
battleAI.choose(battleMon, battle, getSide(), moveset, forceSwitch)
})
} catch (exception: IllegalActionChoiceException) {
// Validation may have consumed forced passes and accepted a prefix before rejecting a later slot.
responses.clear()
expectingPassActions.clear()
expectingPassActions.addAll(passActions)
if (req.forceSwitch.any { it }) {
LOGGER.error("AI could not choose replacements; using Showdown's default choices", exception)
setActionResponses(req.iterate(activePokemon) { _, _, _ -> DefaultActionResponse() })
return
request?.let {
setActionResponses(it.iterate(this.activePokemon) { battleMon, moveset, forceSwitch ->
battleAI.choose(battleMon, battle, getSide(), moveset, forceSwitch)
})
pokemonList.forEach { pokemon ->
pokemon.willBeSwitchedIn = false
}
} ?: {
val response = mutableListOf<ShowdownActionResponse>()
repeat(activePokemon.size) {
response.add(PassActionResponse)
}
setActionResponses(response)
LOGGER.warn("AI requested choice, but no request was set. Returning PassActionResponses.")
}
} catch (exception: IllegalActionChoiceException) {
LOGGER.error("AI was unable to choose an action, we're going to need to pass!")
exception.printStackTrace()
var forcedPasses = passActions.size
setActionResponses(req.iterate(this.activePokemon) { _, moveset, forceSwitch ->
if (!forceSwitch && moveset != null && forcedPasses > 0) {
forcedPasses--
ForcePassActionResponse()
} else PassActionResponse
})
} finally {
pokemonList.forEach { it.willBeSwitchedIn = false }
request?.let {
setActionResponses(it.iterate(this.activePokemon) { _, _ , _->
PassActionResponse
})
} ?: {
val response = mutableListOf<ShowdownActionResponse>()
repeat(activePokemon.size) {
response.add(PassActionResponse)
}
setActionResponses(response)
}
}
}
}
}
@@ -22,11 +22,10 @@ import com.cobblemon.mod.common.item.battle.BagItem
import com.cobblemon.mod.common.net.messages.client.battle.BattleApplyPassResponsePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMakeChoicePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMessagePacket
import java.util.UUID
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.phys.Vec3
import java.util.UUID
abstract class BattleActor(
val uuid: UUID,
@@ -53,8 +52,6 @@ abstract class BattleActor(
var itemsUsed = mutableListOf<BagItem>()
/** For when battles start, it's the number of Pokémon that are still in the process of being sent out (animation wise) */
var stillSendingOutCount = 0
/** Positions follow active slot order: slot a is index 0. */
var stadiumSendOutPositions: List<Vec3>? = null
abstract val type: ActorType
@@ -74,33 +71,23 @@ abstract class BattleActor(
open fun isForPlayer(serverPlayerEntity: ServerPlayer) = serverPlayerEntity.uuid in getPlayerUUIDs()
open fun isForPokemon(pokemonEntity: PokemonEntity) = activePokemon.any { it.battlePokemon?.effectedPokemon?.entity == pokemonEntity }
/** Prepare every actor before notifying any AI, since synchronous choices can dispatch immediately. */
fun prepareTurn() {
mustChoose = false
val req = request ?: run {
responses.clear()
expectingPassActions.clear()
return
}
fun turn() {
val request = request ?: return
responses.clear()
if (activePokemon.any { it.isAlive() }) {
mustChoose = true
sendUpdate(BattleMakeChoicePacket())
}
val requestActive = req.active
if (req.wait || (requestActive.isNullOrEmpty() && req.forceSwitch.none { it })) {
val requestActive = request.active
if (requestActive == null || requestActive.isEmpty() || request.wait) {
this.request = null
expectingPassActions.clear()
mustChoose = false
} else if (req.forceSwitch.any { it }) {
mustChoose = true
return
}
}
/** Call only after every actor has been prepared for this turn. */
fun fireChoiceRequest() {
if (mustChoose) sendUpdate(BattleMakeChoicePacket())
}
fun postUpdate() {
val request = request ?: return
val forceSwitchPokemon = request.forceSwitch.mapIndexedNotNull { index, b -> if (b) activePokemon[index] else null }
@@ -175,4 +162,4 @@ abstract class BattleActor(
open fun win(otherWinners: List<BattleActor>, losers: List<BattleActor>) {}
open fun lose(winners: List<BattleActor>, otherLosers: List<BattleActor>) {}
}
}
@@ -21,6 +21,7 @@ import com.cobblemon.mod.common.util.adapters.*
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import java.awt.Color
import net.minecraft.advancements.critereon.MinMaxBounds
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceLocation
@@ -30,7 +31,6 @@ import net.minecraft.tags.TagKey
import net.minecraft.world.level.biome.Biome
import net.minecraft.world.phys.AABB
import net.minecraft.world.phys.Vec3
import java.awt.Color
/**
* The data registry for [Berry].
@@ -26,10 +26,10 @@ import com.cobblemon.mod.common.util.writeBox
import com.cobblemon.mod.common.util.writeEnumConstant
import com.cobblemon.mod.common.util.writeIdentifier
import com.google.gson.annotations.SerializedName
import net.minecraft.core.BlockPos
import net.minecraft.network.RegistryFriendlyByteBuf
import java.awt.Color
import java.util.EnumSet
import net.minecraft.core.BlockPos
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.tags.TagKey
import net.minecraft.world.entity.LivingEntity
@@ -1,15 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.camera
/** Minecraft yaw and pitch, in degrees. */
data class CameraRotation(
val yaw: Float,
val pitch: Float
)
@@ -1,34 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.camera.model
// Air bubbles have no separate vanilla call that Fabric can cancel.
enum class HudElement(val id: String) {
CROSSHAIR("crosshair"),
HOTBAR("hotbar"),
EXPERIENCE_BAR("experience_bar"),
PLAYER_HEALTH("player_health"),
ARMOR("armor"),
FOOD("food"),
EFFECTS("effects"),
BOSS_BAR("boss_bar"),
SCOREBOARD("scoreboard"),
CHAT("chat"),
PLAYER_LIST("player_list"),
SELECTED_ITEM_NAME("selected_item_name"),
COBBLEMON_OVERLAY("cobblemon_overlay");
companion object {
val ALL: Set<HudElement> = entries.toSet()
private val BY_ID = entries.associateBy { it.id }
fun fromId(id: String): HudElement? = BY_ID[id]
}
}
@@ -1,27 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.camera.model
data class ParameterDefinition(
val type: ParameterType,
val description: String? = null,
val default: ParameterDefault? = null
)
enum class ParameterType {
NUMBER,
VEC3,
STRING
}
sealed class ParameterDefault {
data class NumberDefault(val value: Double) : ParameterDefault()
data class Vec3Default(val x: Double, val y: Double, val z: Double) : ParameterDefault()
data class StringDefault(val value: String) : ParameterDefault()
}
@@ -1,126 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.camera.model
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolve
import com.google.gson.JsonElement
import net.minecraft.world.phys.Vec3
data class PositionExpression(
val x: CoordinateValue,
val y: CoordinateValue,
val z: CoordinateValue
) {
fun toVec3(
context: Map<String, MoValue> = emptyMap(),
runtime: MoLangRuntime,
origin: Vec3 = Vec3.ZERO,
isRelative: Boolean = false
): Vec3 {
val base = Vec3(
x.evaluate(context, runtime),
y.evaluate(context, runtime),
z.evaluate(context, runtime)
)
return if (isRelative) base.add(origin) else base
}
fun isFinite(context: Map<String, MoValue>, runtime: MoLangRuntime): Boolean {
val vec = toVec3(context, runtime)
return vec.x.isFinite() && vec.y.isFinite() && vec.z.isFinite()
}
companion object {
fun fromJson(element: JsonElement): PositionExpression {
return when {
element.isJsonObject -> {
val obj = element.asJsonObject
PositionExpression(
x = deserializeCoordinate(obj.get("x")),
y = deserializeCoordinate(obj.get("y")),
z = deserializeCoordinate(obj.get("z"))
)
}
element.isJsonArray -> {
val arr = element.asJsonArray
if (arr.size() != 3) {
throw IllegalArgumentException("Position array must have exactly 3 elements [x, y, z], got ${arr.size()}")
}
PositionExpression(
x = deserializeCoordinate(arr[0]),
y = deserializeCoordinate(arr[1]),
z = deserializeCoordinate(arr[2])
)
}
else -> {
throw IllegalArgumentException("Position must be either an object {x, y, z} or array [x, y, z]")
}
}
}
private fun deserializeCoordinate(element: JsonElement?): CoordinateValue {
if (element == null) {
return CoordinateValue.Static(0.0)
}
return when {
element.isJsonPrimitive && element.asJsonPrimitive.isNumber -> {
CoordinateValue.Static(element.asDouble)
}
element.isJsonPrimitive && element.asJsonPrimitive.isString -> {
CoordinateValue.Dynamic(element.asString.asExpressionLike())
}
element.isJsonObject -> {
val obj = element.asJsonObject
val type = obj.get("type")?.asString
val expression = obj.get("expression")?.asString
when (type) {
"expression" -> {
if (expression == null) {
throw IllegalArgumentException("Expression coordinate missing 'expression' field")
}
CoordinateValue.Dynamic(expression.asExpressionLike())
}
else -> {
throw IllegalArgumentException("Unknown coordinate type: $type")
}
}
}
else -> {
throw IllegalArgumentException("Invalid coordinate value: $element")
}
}
}
}
}
sealed class CoordinateValue {
data class Static(val value: Double) : CoordinateValue() {
init { require(value.isFinite()) { "Static coordinate must be finite" } }
}
data class Dynamic(val expression: ExpressionLike) : CoordinateValue()
fun evaluate(
context: Map<String, MoValue>,
runtime: MoLangRuntime
): Double {
return when (this) {
is Static -> value
is Dynamic -> runtime.resolve(expression, context).asDouble().also {
require(it.isFinite()) { "Dynamic coordinate must evaluate to a finite value" }
}
}
}
}
@@ -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.api.camera.result
import net.minecraft.network.chat.Component
data class ValidationError(
val path: String,
val message: Component,
val severity: Severity = Severity.ERROR
) {
enum class Severity { WARNING, ERROR }
override fun toString(): String = "[$severity] $path: ${message.string}"
}
@@ -1,49 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.Entity
sealed class ActorBinding {
abstract val kind: ActorKind
/** Visible player actors override server position and suppress movement packets. */
data class Player(
val player: ServerPlayer,
val fallbackPokemon: PokemonProperties? = null
) : ActorBinding() {
override val kind: ActorKind = ActorKind.PlayerTakeover
}
data class Real(val entity: Entity) : ActorBinding() {
override val kind: ActorKind = ActorKind.RealEntity
}
data class SynthPokemon(
val properties: PokemonProperties,
val aspects: Set<String> = emptySet()
) : ActorBinding() {
override val kind: ActorKind = ActorKind.SynthesizedPokemon
}
data class SynthBedrock(
val category: ResourceLocation,
val aspects: Set<String> = emptySet(),
val scale: Float = 1.0f
) : ActorBinding() {
override val kind: ActorKind = ActorKind.SynthesizedBedrock
init {
require(scale.isFinite() && scale > 0f) { "SynthBedrock scale must be positive, got $scale" }
}
}
}
@@ -1,28 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model
data class ActorDeclaration(
val id: String,
val kind: ActorKind
) {
init {
require(id.isNotBlank()) { "ActorDeclaration id must be non-blank" }
}
}
sealed class ActorKind {
object PlayerTakeover : ActorKind()
object RealEntity : ActorKind()
object SynthesizedPokemon : ActorKind()
object SynthesizedBedrock : ActorKind()
}
@@ -1,27 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model
import com.cobblemon.mod.common.api.cinematic.model.tracks.ActorTrack
/** Null visibility carries over between beats; tracks never carry over. */
data class ActorDirection(
val visible: Boolean? = null,
val startPose: StartPose? = null,
val startPoseMode: StartPoseMode? = null,
val tracks: List<ActorTrack> = emptyList()
) {
init {
if (startPose != null) {
require(visible != false) {
"ActorDirection.startPose declared but visible = false; hidden actors cannot have a start pose"
}
}
}
}
@@ -1,33 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model
import com.cobblemon.mod.common.api.camera.model.HudElement
/** Null duration leaves the beat unbounded; feeds without cuts are inactive. */
data class Beat(
val id: String,
val duration: Float? = null,
val isLooping: Boolean = false,
val speed: Float = 1.0f,
val actorDirections: Map<String, ActorDirection> = emptyMap(),
val cuts: Map<String, CutTrack> = emptyMap(),
val guiTrack: SceneGuiTrack? = null,
val renderPlayerBody: Boolean = true,
val hiddenHudElements: Set<HudElement> = emptySet(),
val cues: List<SceneCue> = emptyList()
) {
init {
require(id.isNotBlank()) { "Beat id must be non-blank" }
require(speed.isFinite() && speed > 0f) { "Beat speed must be positive, got $speed" }
duration?.let {
require(it.isFinite() && it >= 0f) { "Beat duration must be non-negative, got $it" }
}
}
}
@@ -1,25 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model
import com.cobblemon.mod.common.api.molang.ExpressionLike
/** Clamping at a beat's duration does not end the scene; completion requires an explicit transition. */
data class BeatTransition(
val sourceBeatId: String,
val targetBeatId: String,
val condition: ExpressionLike,
val transition: CutTransition = CutTransition.Blend(0.4f),
val endsScene: Boolean = false
) {
init {
require(sourceBeatId.isNotBlank()) { "BeatTransition sourceBeatId must be non-blank" }
require(endsScene || targetBeatId.isNotBlank()) { "BeatTransition targetBeatId must be non-blank" }
}
}
@@ -1,13 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model
import net.minecraft.network.chat.Component
class CinematicValidationException(val reason: Component) : IllegalArgumentException(reason.string)
@@ -1,41 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model
data class CutTrack(
val entries: List<CutEntry>
) {
init {
require(entries.isNotEmpty()) { "CutTrack must have at least one entry" }
require(entries.zipWithNext().all { (a, b) -> a.time <= b.time }) {
"CutTrack entries must be sorted ascending by time"
}
}
}
data class CutEntry(
val time: Float,
val shotId: String,
val transition: CutTransition = CutTransition.Instant
) {
init {
require(time.isFinite() && time >= 0f) { "CutEntry time must be non-negative, got $time" }
require(shotId.isNotBlank()) { "CutEntry shotId must be non-blank" }
}
}
sealed class CutTransition {
object Instant : CutTransition()
data class Blend(val duration: Float) : CutTransition() {
init {
require(duration.isFinite() && duration > 0f) { "Blend duration must be positive, got $duration" }
}
}
}
@@ -1,16 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model
enum class DisconnectPolicy {
END_SCENE,
SUBSTITUTE,
HIDE_ACTOR,
FAIL
}
@@ -1,48 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model
data class FeedDeclaration(
val id: String,
val kind: FeedKind
) {
init {
require(id.isNotBlank()) { "FeedDeclaration id must be non-blank" }
}
companion object {
/** Bound for feed counts read off the wire, so a crafted packet can't drive a huge allocation. */
const val MAX_FEEDS = 64
}
}
sealed class FeedKind {
/** Occupies the full viewport. */
object Fullscreen : FeedKind()
/** Picture-in-picture overlay in a viewport corner. [size] is a fraction of viewport. */
data class Pip(val corner: Corner, val size: Float) : FeedKind() {
init {
require(size > 0f && size <= 1f) { "Pip size must be in (0, 1], got $size" }
}
}
/** Relative share of a paired split. */
data class Split(val side: Side, val size: Float) : FeedKind() {
init {
require(size > 0f && size <= 1f) { "Split size must be in (0, 1], got $size" }
}
}
data class Diagonal(val half: DiagonalHalf) : FeedKind()
enum class Corner { TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT }
enum class Side { LEFT, RIGHT, TOP, BOTTOM }
enum class DiagonalHalf { UPPER, LOWER }
}
@@ -1,23 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model
fun <T> orderedKeyframes(keyframes: List<T>, time: (T) -> Float): List<T> {
require(keyframes.isNotEmpty()) { "At least one keyframe is required" }
require(keyframes.all { time(it).isFinite() && time(it) >= 0f }) { "Keyframe times must be finite and nonnegative" }
val ordered = ArrayList<T>(keyframes.size)
for (keyframe in keyframes.sortedBy(time)) {
if (ordered.isNotEmpty() && time(ordered.last()) == time(keyframe)) {
ordered[ordered.lastIndex] = keyframe
} else {
ordered.add(keyframe)
}
}
return ordered
}
@@ -1,231 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model
import net.minecraft.network.chat.Component
import com.cobblemon.mod.common.api.cinematic.runtime.ActorFraming
import com.cobblemon.mod.common.api.camera.model.ParameterDefinition
import com.cobblemon.mod.common.api.camera.result.ValidationError
import com.cobblemon.mod.common.api.cinematic.runtime.ActorDependencyOrder
import com.cobblemon.mod.common.api.cinematic.model.sources.builtin.OrbitPosition
import com.cobblemon.mod.common.api.cinematic.model.sources.builtin.LookAt
import com.cobblemon.mod.common.api.cinematic.model.sources.builtin.LookAtTarget
data class Scene(
val id: String,
val parameters: Map<String, ParameterDefinition> = emptyMap(),
val actors: Map<String, ActorDeclaration> = emptyMap(),
val shots: Map<String, Shot> = emptyMap(),
val feeds: List<FeedDeclaration> = emptyList(),
val startBeatId: String,
val beats: Map<String, Beat>,
val transitions: List<BeatTransition> = emptyList(),
val version: Int = 2,
val damageImmunityDuringTakeover: Boolean = false,
val disconnectPolicy: DisconnectPolicy = DisconnectPolicy.END_SCENE
) {
init {
require(id.isNotBlank()) { "Scene id must be non-blank" }
require(startBeatId.isNotBlank()) { "Scene startBeatId must be non-blank" }
require(version == 2) { "Scene.version must be 2, got $version" }
}
fun getBeat(beatId: String): Beat? = beats[beatId]
fun getShot(shotId: String): Shot? = shots[shotId]
fun getActor(actorId: String): ActorDeclaration? = actors[actorId]
fun getFeed(feedId: String): FeedDeclaration? = feeds.firstOrNull { it.id == feedId }
fun getTransitionsFrom(beatId: String): List<BeatTransition> =
transitions.filter { it.sourceBeatId == beatId }
fun validate(): List<ValidationError> {
val errors = mutableListOf<ValidationError>()
if (startBeatId !in beats) {
errors.add(ValidationError(
path = "startBeatId",
message = Component.translatable("cobblemon.cinematic_editor.validation.start_missing", startBeatId)
))
}
actors.forEach { (key, actor) ->
if (actor.id != key) {
errors.add(ValidationError(
path = "actors[$key].id",
message = Component.translatable("cobblemon.cinematic_editor.validation.actor_id", key, actor.id)
))
}
}
shots.forEach { (key, shot) ->
val framingActors = (shot.position as? OrbitPosition)?.actorIds.orEmpty() +
listOfNotNull((shot.position as? OrbitPosition)?.bearingActorId) +
((shot.rotation as? LookAt)?.target as? LookAtTarget.Actors)?.actorIds.orEmpty()
framingActors.distinct().filter { it !in actors && it !in ActorFraming.groups }.forEach { actorId ->
errors.add(ValidationError(path = "shots[$key]", message = Component.translatable("cobblemon.cinematic_editor.validation.framing_actor", actorId)))
}
if (shot.id != key) {
errors.add(ValidationError(
path = "shots[$key].id",
message = Component.translatable("cobblemon.cinematic_editor.validation.shot_id", key, shot.id)
))
}
}
val feedIds = feeds.map { it.id }
val duplicateFeedIds = feedIds.groupingBy { it }.eachCount().filter { it.value > 1 }.keys
duplicateFeedIds.forEach { duplicateId ->
errors.add(ValidationError(
path = "feeds",
message = Component.translatable("cobblemon.cinematic_editor.validation.duplicate_feed", duplicateId)
))
}
val cueIds = mutableSetOf<String>()
beats.forEach { (beatKey, beat) ->
beat.actorDirections.forEach { (actorId, direction) ->
if (direction.tracks.any { it.trackType == "pathfinding" } &&
direction.tracks.count { it.trackType in setOf("pathfinding", "spline_movement", "keyframe_movement", "follow_actor", "attach", "pose_lock") } > 1) {
errors.add(ValidationError(
path = "beats[$beatKey].actorDirections[$actorId].tracks",
message = Component.translatable("cobblemon.cinematic_editor.validation.movement_conflict")
))
}
}
beat.cues.forEachIndexed { index, cue ->
if (!cueIds.add(cue.id)) errors.add(ValidationError(
path = "beats[$beatKey].cues[$index].id", message = Component.translatable("cobblemon.cinematic_editor.validation.duplicate_cue", cue.id)))
if (beat.duration != null && cue.time > beat.duration) errors.add(ValidationError(
path = "beats[$beatKey].cues[$index].time", message = Component.translatable("cobblemon.cinematic_editor.validation.late_cue", cue.id)))
}
try {
ActorDependencyOrder.resolve(actors.keys, beat)
} catch (error: CinematicValidationException) {
errors.add(ValidationError(path = "beats[$beatKey].actorDirections", message = error.reason))
}
if (beat.id != beatKey) {
errors.add(ValidationError(
path = "beats[$beatKey].id",
message = Component.translatable("cobblemon.cinematic_editor.validation.beat_id", beatKey, beat.id)
))
}
beat.actorDirections.keys.forEach { actorRef ->
if (actorRef !in actors) {
errors.add(ValidationError(
path = "beats[$beatKey].actorDirections[$actorRef]",
message = Component.translatable("cobblemon.cinematic_editor.validation.actor_missing", actorRef)
))
}
}
beat.cuts.forEach { (feedRef, cutTrack) ->
if (feedRef !in feedIds) {
errors.add(ValidationError(
path = "beats[$beatKey].cuts[$feedRef]",
message = Component.translatable("cobblemon.cinematic_editor.validation.feed_missing", feedRef)
))
}
cutTrack.entries.forEach { entry ->
if (entry.shotId !in shots) {
errors.add(ValidationError(
path = "beats[$beatKey].cuts[$feedRef]",
message = Component.translatable("cobblemon.cinematic_editor.validation.shot_missing", entry.shotId, entry.time)
))
}
}
}
}
transitions.forEachIndexed { index, transition ->
if (transition.sourceBeatId !in beats) {
errors.add(ValidationError(
path = "transitions[$index].sourceBeatId",
message = Component.translatable("cobblemon.cinematic_editor.validation.source_missing", transition.sourceBeatId)
))
}
if (!transition.endsScene && transition.targetBeatId !in beats) {
errors.add(ValidationError(
path = "transitions[$index].targetBeatId",
message = Component.translatable("cobblemon.cinematic_editor.validation.target_missing", transition.targetBeatId)
))
}
}
val graph = transitions.filter { !it.endsScene && it.sourceBeatId in beats && it.targetBeatId in beats }
.groupBy({ it.sourceBeatId }, { it.targetBeatId })
val reachable = findReachableBeats(graph)
beats.keys.forEach { beatId ->
if (beatId !in reachable) {
errors.add(ValidationError(
path = "beats[$beatId]",
message = Component.translatable("cobblemon.cinematic_editor.validation.unreachable", startBeatId),
severity = ValidationError.Severity.WARNING
))
}
}
val cycle = findCycle(graph)
if (cycle != null) {
errors.add(ValidationError(
path = "transitions",
message = Component.translatable("cobblemon.cinematic_editor.validation.cycle", cycle.joinToString(" -> ")),
severity = ValidationError.Severity.WARNING
))
}
return errors
}
private fun findReachableBeats(graph: Map<String, List<String>>): Set<String> {
val reachable = mutableSetOf<String>()
val queue = ArrayDeque<String>()
if (startBeatId in beats) {
queue.add(startBeatId)
reachable.add(startBeatId)
}
while (queue.isNotEmpty()) {
for (target in graph[queue.removeFirst()].orEmpty()) {
if (reachable.add(target)) queue.addLast(target)
}
}
return reachable
}
private fun findCycle(graph: Map<String, List<String>>): List<String>? {
val visited = mutableSetOf<String>()
val active = mutableMapOf<String, Int>()
val path = mutableListOf<String>()
val stack = ArrayDeque<Iterator<String>>()
fun enter(id: String) {
visited.add(id)
active[id] = path.size
path.add(id)
stack.addLast(graph[id].orEmpty().iterator())
}
for (id in beats.keys) {
if (id in visited) continue
enter(id)
while (stack.isNotEmpty()) {
val remaining = stack.last()
if (remaining.hasNext()) {
val target = remaining.next()
val cycleStart = active[target]
if (cycleStart != null) return path.subList(cycleStart, path.size) + target
if (target !in visited) enter(target)
} else {
stack.removeLast()
active.remove(path.removeAt(path.lastIndex))
}
}
}
return null
}
}
@@ -1,17 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model
/** A scene-unique, one-shot signal; loops and beat re-entry never fire it again. */
data class SceneCue(val id: String, val time: Float) {
init {
require(id.isNotBlank() && id.length <= 128) { "Cue id must contain 1 to 128 characters" }
require(time.isFinite() && time >= 0f) { "Cue time must be finite and non-negative" }
}
}
@@ -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.api.cinematic.model
data class SceneGuiTrack(
val actions: List<SceneGuiAction>
) {
init {
require(actions.zipWithNext().all { (a, b) -> a.time <= b.time }) {
"SceneGuiTrack actions must be sorted by time"
}
}
}
data class SceneGuiAction(
val time: Float,
val type: SceneGuiActionType,
val guiId: String,
val args: Map<String, SceneGuiArgValue> = emptyMap()
) {
init {
require(time.isFinite() && time >= 0f) { "SceneGuiAction time must be non-negative, got $time" }
}
}
enum class SceneGuiActionType {
OPEN,
CLOSE,
UPDATE_ARGS
}
sealed class SceneGuiArgValue {
data class Expression(val value: String) : SceneGuiArgValue()
data class StringLiteral(val value: String) : SceneGuiArgValue()
}
@@ -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.api.cinematic.model
import com.cobblemon.mod.common.api.cinematic.model.sources.FovSource
import com.cobblemon.mod.common.api.cinematic.model.sources.Lens
import com.cobblemon.mod.common.api.cinematic.model.sources.PositionSource
import com.cobblemon.mod.common.api.cinematic.model.sources.RollSource
import com.cobblemon.mod.common.api.cinematic.model.sources.RotationSource
import com.cobblemon.mod.common.api.cinematic.model.sources.ShotModifier
data class Shot(
val id: String,
val position: PositionSource,
val rotation: RotationSource,
val fov: FovSource? = null,
val roll: RollSource? = null,
val lens: Lens? = null,
val modifiers: List<ShotModifier> = emptyList()
) {
init {
require(id.isNotBlank()) { "Shot id must be non-blank" }
}
}
@@ -1,34 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model
import com.cobblemon.mod.common.api.camera.CameraRotation
import com.cobblemon.mod.common.api.camera.model.PositionExpression
data class StartPose(
val position: PositionExpression,
val rotation: CameraRotation,
val blendDurationSeconds: Float = 0.5f
) {
init {
require(rotation.yaw.isFinite() && rotation.pitch.isFinite()) { "Start pose rotation must be finite" }
require(blendDurationSeconds.isFinite() && blendDurationSeconds >= 0f) { "Start pose blend duration must be finite and nonnegative" }
}
}
/** Unset mode teleports newly visible actors and ignores the start pose for already visible actors. */
enum class StartPoseMode {
TELEPORT,
BLEND,
EXPECT,
IGNORE
}
@@ -1,23 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model.sources
data class Lens(
val aspectCrop: Float? = null,
val letterbox: Float = 0f
) {
init {
aspectCrop?.let {
require(it.isFinite() && it > 0f) { "Lens aspectCrop must be positive, got $it" }
}
require(letterbox >= 0f && letterbox <= 0.5f) {
"Lens letterbox must be in [0, 0.5], got $letterbox"
}
}
}
@@ -1,13 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model.sources
abstract class PositionSource {
abstract val type: String
}
@@ -1,13 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model.sources
abstract class RollSource {
abstract val type: String
}
@@ -1,13 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model.sources
abstract class RotationSource {
abstract val type: String
}
@@ -1,13 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model.sources
abstract class ShotModifier {
abstract val type: String
}
@@ -1,43 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model.sources.builtin
import com.cobblemon.mod.common.api.cinematic.model.sources.ShotModifier
import com.google.gson.JsonObject
import net.minecraft.world.phys.Vec3
data class ConstraintModifier(
val minX: Double? = null, val maxX: Double? = null,
val minY: Double? = null, val maxY: Double? = null,
val minZ: Double? = null, val maxZ: Double? = null
) : ShotModifier() {
override val type: String = TYPE
init {
require(listOfNotNull(minX, maxX, minY, maxY, minZ, maxZ).all { it.isFinite() }) { "Constraint bounds must be finite" }
require(minX == null || maxX == null || minX <= maxX) { "Minimum X must not exceed maximum X" }
require(minY == null || maxY == null || minY <= maxY) { "Minimum Y must not exceed maximum Y" }
require(minZ == null || maxZ == null || minZ <= maxZ) { "Minimum Z must not exceed maximum Z" }
}
fun apply(pos: Vec3): Vec3 = Vec3(
pos.x.let { if (minX != null && it < minX) minX else if (maxX != null && it > maxX) maxX else it },
pos.y.let { if (minY != null && it < minY) minY else if (maxY != null && it > maxY) maxY else it },
pos.z.let { if (minZ != null && it < minZ) minZ else if (maxZ != null && it > maxZ) maxZ else it }
)
companion object {
const val TYPE = "constraint"
fun fromJson(obj: JsonObject): ConstraintModifier = ConstraintModifier(
minX = obj.get("minX")?.asDouble, maxX = obj.get("maxX")?.asDouble,
minY = obj.get("minY")?.asDouble, maxY = obj.get("maxY")?.asDouble,
minZ = obj.get("minZ")?.asDouble, maxZ = obj.get("maxZ")?.asDouble
)
}
}
@@ -1,56 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model.sources.builtin
import kotlin.math.cos
import kotlin.math.sin
import com.cobblemon.mod.common.api.cinematic.model.sources.PositionSource
import com.google.gson.JsonObject
import net.minecraft.world.phys.Vec3
data class CranePosition(
val pivot: Vec3,
val armLength: Float,
val startAngleDeg: Float,
val angularVelocityDegPerSec: Float,
val height: Float = 0f
) : PositionSource() {
override val type: String = TYPE
init {
require(armLength.isFinite() && armLength > 0f) { "CranePosition armLength must be finite and positive" }
require(startAngleDeg.isFinite() && angularVelocityDegPerSec.isFinite() && height.isFinite()) {
"CranePosition angles, speed and height must be finite"
}
require(pivot.x.isFinite() && pivot.y.isFinite() && pivot.z.isFinite()) { "CranePosition pivot must be finite" }
}
fun evaluate(time: Float): Vec3 {
val angleRad = Math.toRadians(startAngleDeg + angularVelocityDegPerSec.toDouble() * time)
return Vec3(
pivot.x + armLength * cos(angleRad),
pivot.y + height,
pivot.z + armLength * sin(angleRad)
)
}
companion object {
const val TYPE = "crane"
fun fromJson(obj: JsonObject): CranePosition {
val p = obj.getAsJsonObject("pivot")
return CranePosition(
pivot = Vec3(p.get("x").asDouble, p.get("y").asDouble, p.get("z").asDouble),
armLength = obj.get("armLength").asFloat,
startAngleDeg = obj.get("startAngle")?.asFloat ?: 0f,
angularVelocityDegPerSec = obj.get("angularVelocity").asFloat,
height = obj.get("height")?.asFloat ?: 0f
)
}
}
}
@@ -1,50 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model.sources.builtin
import com.cobblemon.mod.common.api.cinematic.model.sources.PositionSource
import com.google.gson.JsonObject
import net.minecraft.world.phys.Vec3
data class DollyPosition(
val from: Vec3,
val to: Vec3,
val duration: Float
) : PositionSource() {
override val type: String = TYPE
init {
require(duration.isFinite() && duration > 0f) { "DollyPosition duration must be finite and positive" }
require(listOf(from.x, from.y, from.z, to.x, to.y, to.z).all { it.isFinite() }) {
"DollyPosition endpoints must be finite"
}
}
fun evaluate(time: Float): Vec3 {
val t = (time / duration).coerceIn(0f, 1f)
return Vec3(
from.x + (to.x - from.x) * t,
from.y + (to.y - from.y) * t,
from.z + (to.z - from.z) * t
)
}
companion object {
const val TYPE = "dolly"
fun fromJson(obj: JsonObject): DollyPosition {
val f = obj.getAsJsonObject("from")
val t = obj.getAsJsonObject("to")
return DollyPosition(
from = Vec3(f.get("x").asDouble, f.get("y").asDouble, f.get("z").asDouble),
to = Vec3(t.get("x").asDouble, t.get("y").asDouble, t.get("z").asDouble),
duration = obj.get("duration").asFloat
)
}
}
}
@@ -1,60 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model.sources.builtin
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.cinematic.model.sources.FovSource
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveDouble
import com.google.gson.JsonObject
import java.util.concurrent.atomic.AtomicBoolean
data class ExpressionFov(
val expression: ExpressionLike,
val fallbackFov: Float = 70f
) : FovSource() {
override val type: String = "expression"
@Transient private val warningReported = AtomicBoolean()
init {
require(fallbackFov in 1f..179f) { "ExpressionFov fallbackFov must be in [1, 179]" }
}
fun evaluate(runtime: MoLangRuntime): Float {
return try {
// coerceIn does not filter NaN — its comparisons are false either way — so check first.
val raw = runtime.resolveDouble(expression).toFloat()
if (!raw.isFinite()) {
if (warningReported.compareAndSet(false, true)) {
Cobblemon.LOGGER.warn("[ExpressionFov] Non-finite result $raw; using fallback $fallbackFov")
}
fallbackFov
} else {
raw.coerceIn(1f, 179f)
}
} catch (e: Exception) {
if (warningReported.compareAndSet(false, true)) {
Cobblemon.LOGGER.warn("[ExpressionFov] Evaluation failed: ${e.message}; using fallback $fallbackFov", e)
}
fallbackFov
}
}
companion object {
const val TYPE = "expression"
fun fromJson(obj: JsonObject): ExpressionFov {
val exprStr = obj.get("expression")?.asString
?: throw IllegalArgumentException("ExpressionFov missing 'expression' field")
val fallback = obj.get("fallback")?.asFloat ?: 70f
return ExpressionFov(expression = exprStr.asExpressionLike(), fallbackFov = fallback)
}
}
}
@@ -1,79 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model.sources.builtin
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.cinematic.model.sources.PositionSource
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveDouble
import com.google.gson.JsonObject
import net.minecraft.world.phys.Vec3
import java.util.concurrent.atomic.AtomicBoolean
data class ExpressionVec3Position(
val xExpression: ExpressionLike,
val yExpression: ExpressionLike,
val zExpression: ExpressionLike,
val fallback: Vec3 = Vec3.ZERO
) : PositionSource() {
override val type: String = "expression_vec3"
@Transient private val warningReported = AtomicBoolean()
init {
require(fallback.x.isFinite() && fallback.y.isFinite() && fallback.z.isFinite()) { "Expression position fallback must be finite" }
}
fun evaluate(runtime: MoLangRuntime?): Vec3 {
if (runtime == null) return fallback
return try {
val x = runtime.resolveDouble(xExpression)
val y = runtime.resolveDouble(yExpression)
val z = runtime.resolveDouble(zExpression)
// MoLang can return NaN or infinity without throwing, so validate before sending transforms.
if (!x.isFinite() || !y.isFinite() || !z.isFinite()) {
if (warningReported.compareAndSet(false, true)) {
Cobblemon.LOGGER.warn("[ExpressionVec3Position] Non-finite result ($x, $y, $z); using fallback $fallback")
}
fallback
} else {
Vec3(x, y, z)
}
} catch (e: Exception) {
if (warningReported.compareAndSet(false, true)) {
Cobblemon.LOGGER.warn("[ExpressionVec3Position] Evaluation failed: ${e.message}; using fallback $fallback", e)
}
fallback
}
}
companion object {
const val TYPE = "expression_vec3"
fun fromJson(obj: JsonObject): ExpressionVec3Position {
val x = obj.get("x")?.asString
?: throw IllegalArgumentException("ExpressionVec3Position missing 'x'")
val y = obj.get("y")?.asString
?: throw IllegalArgumentException("ExpressionVec3Position missing 'y'")
val z = obj.get("z")?.asString
?: throw IllegalArgumentException("ExpressionVec3Position missing 'z'")
val fb = obj.get("fallback")?.asJsonObject
val fallback = if (fb != null) {
Vec3(fb.get("x").asDouble, fb.get("y").asDouble, fb.get("z").asDouble)
} else Vec3.ZERO
return ExpressionVec3Position(
xExpression = x.asExpressionLike(),
yExpression = y.asExpressionLike(),
zExpression = z.asExpressionLike(),
fallback = fallback
)
}
}
}
@@ -1,25 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model.sources.builtin
import com.cobblemon.mod.common.api.cinematic.model.sources.FovSource
import com.google.gson.JsonObject
data class FixedFov(val fov: Float) : FovSource() {
override val type: String = "fixed"
init {
require(fov in 1f..179f) { "FixedFov must be in [1, 179], got $fov" }
}
companion object {
const val TYPE = "fixed"
fun fromJson(obj: JsonObject): FixedFov = FixedFov(obj.get("value").asFloat)
}
}
@@ -1,29 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model.sources.builtin
import com.cobblemon.mod.common.api.cinematic.model.sources.PositionSource
import com.google.gson.JsonObject
import net.minecraft.world.phys.Vec3
data class FixedPosition(val position: Vec3) : PositionSource() {
override val type: String = "fixed"
init {
require(position.x.isFinite() && position.y.isFinite() && position.z.isFinite()) { "Fixed position must be finite" }
}
companion object {
const val TYPE = "fixed"
fun fromJson(obj: JsonObject): FixedPosition {
val pos = obj.getAsJsonObject("position") ?: throw IllegalArgumentException("FixedPosition missing 'position'")
return FixedPosition(Vec3(pos.get("x").asDouble, pos.get("y").asDouble, pos.get("z").asDouble))
}
}
}
@@ -1,25 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model.sources.builtin
import com.cobblemon.mod.common.api.cinematic.model.sources.RollSource
import com.google.gson.JsonObject
data class FixedRoll(val roll: Float) : RollSource() {
override val type: String = "fixed"
init {
require(roll.isFinite()) { "Fixed roll must be finite" }
}
companion object {
const val TYPE = "fixed"
fun fromJson(obj: JsonObject): FixedRoll = FixedRoll(obj.get("value").asFloat)
}
}
@@ -1,31 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model.sources.builtin
import com.cobblemon.mod.common.api.camera.CameraRotation
import com.cobblemon.mod.common.api.cinematic.model.sources.RotationSource
import com.google.gson.JsonObject
data class FixedRotation(val rotation: CameraRotation) : RotationSource() {
override val type: String = "fixed"
init {
require(rotation.yaw.isFinite() && rotation.pitch.isFinite()) { "Fixed rotation must be finite" }
}
companion object {
const val TYPE = "fixed"
fun fromJson(obj: JsonObject): FixedRotation {
return FixedRotation(CameraRotation(
yaw = obj.get("yaw").asFloat,
pitch = obj.get("pitch").asFloat
))
}
}
}
@@ -1,41 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model.sources.builtin
import com.cobblemon.mod.common.api.cinematic.model.sources.PositionSource
import com.google.gson.JsonObject
import net.minecraft.world.phys.Vec3
/** Offset is world-space and ignores actor orientation. */
data class FollowActorPosition(
val actorId: String,
val offset: Vec3,
val fallback: Vec3 = Vec3.ZERO
) : PositionSource() {
override val type: String = TYPE
init {
require(listOf(offset.x, offset.y, offset.z, fallback.x, fallback.y, fallback.z).all { it.isFinite() }) {
"FollowActorPosition offset and fallback must be finite"
}
}
companion object {
const val TYPE = "follow_actor"
fun fromJson(obj: JsonObject): FollowActorPosition {
val o = obj.getAsJsonObject("offset")
val fObj = obj.getAsJsonObject("fallback")
return FollowActorPosition(
actorId = obj.get("actorId").asString,
offset = Vec3(o.get("x").asDouble, o.get("y").asDouble, o.get("z").asDouble),
fallback = if (fObj != null) Vec3(fObj.get("x").asDouble, fObj.get("y").asDouble, fObj.get("z").asDouble) else Vec3.ZERO
)
}
}
}
@@ -1,53 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cinematic.model.sources.builtin
import com.cobblemon.mod.common.api.cinematic.model.sources.FovSource
import com.cobblemon.mod.common.api.cinematic.model.orderedKeyframes
import com.google.gson.JsonObject
data class KeyframeFov(val keyframes: List<Kf>) : FovSource() {
override val type: String = TYPE
data class Kf(val time: Float, val fov: Float)
init {
keyframes.forEach { require(it.fov in 1f..179f) { "Fov must be in [1, 179], got ${it.fov}" } }
}
@Transient private val playbackKeyframes = orderedKeyframes(keyframes) { it.time }
fun evaluate(time: Float): Float {
val keyframes = playbackKeyframes
if (keyframes.size == 1) return keyframes[0].fov
if (time <= keyframes.first().time) return keyframes.first().fov
if (time >= keyframes.last().time) return keyframes.last().fov
for (i in 0 until keyframes.size - 1) {
val a = keyframes[i]
val b = keyframes[i + 1]
if (time >= a.time && time <= b.time) {
val d = b.time - a.time
val t = if (d > 0f) (time - a.time) / d else 0f
return a.fov + (b.fov - a.fov) * t
}
}
return keyframes.last().fov
}
companion object {
const val TYPE = "keyframe"
fun fromJson(obj: JsonObject): KeyframeFov {
val kfs = obj.getAsJsonArray("keyframes").map { el ->
val k = el.asJsonObject
Kf(time = k.get("time").asFloat, fov = k.get("fov").asFloat)
}
return KeyframeFov(kfs)
}
}
}

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