Compare commits

...
Author SHA1 Message Date
apion 7b3fd8206e Got rotations working for locator bound riders (kinda) 2025-02-08 20:15:21 -05:00
apion e211095317 Player model now stays tethered to seat locator when riding 2025-02-07 21:37:33 -05:00
JPAK b9675ef25c Wrap PlayerRenderer properly now. 2025-02-07 20:29:08 -06:00
apion e25802ab74 Changed bird controller so movement is dependent on pitch and roll 2025-02-07 18:46:55 -05:00
Paul fdc9d48bd6 Reworking generic liquid controller 2025-02-03 18:54:33 +10:00
Paul 74dcbc3e17 Added optional player animations to riding (Lapras as example) 2025-02-01 19:09:51 +10:00
Paul 832999850e Wait put that back 2025-02-01 17:35:42 +10:00
Paul 93b0f40c80 Added vehicle land controller (REVAVROOOOM) 2025-02-01 17:35:14 +10:00
Paul d1928f5b43 Added fall_to_flight controller and polished gliding on Gliscor 2025-02-01 10:22:55 +10:00
Paul 5374fe251d Merge branch 'main' into means-of-transportation
# Conflicts:
#	common/src/main/resources/data/cobblemon/species/generation1/aerodactyl.json
#	common/src/main/resources/data/cobblemon/species/generation1/charizard.json
#	common/src/main/resources/data/cobblemon/species/generation1/lapras.json
#	common/src/main/resources/data/cobblemon/species/generation4/bidoof.json
#	common/src/main/resources/data/cobblemon/species/generation4/gliscor.json
2025-01-31 20:55:59 +10:00
Hiroku 36169db388 Merge branch 'feature/save-file-juggling' into 'main'
old and temp files for everyone

See merge request cable-mc/cobblemon!1484
2025-01-31 07:46:10 +00:00
Paul 1900999a74 Changelogging [skip-ci] 2025-01-31 17:41:56 +10:00
Hiroku ab16814cd2 Merge branch 'fix-setpageondefaultdialoguepage' into 'main'
fix: calling setPages() when initializing the dialogue so default pages can have their timeout scheduled

Closes #1406

See merge request cable-mc/cobblemon!1504
2025-01-31 07:41:29 +00:00
Hiroku 9f622fcd74 Merge branch 'pc-box-2-fix' into 'main'
Fix PC opening on Box 2

See merge request cable-mc/cobblemon!1505
2025-01-31 07:40:16 +00:00
Hiroku 956e2c43b8 Merge branch 'feat-winners-and-losers' into 'main'
feat: set winners and losers on PokemonBattle end

See merge request cable-mc/cobblemon!1501
2025-01-31 07:37:14 +00:00
Hiroku 130f87c9f7 Merge branch 'strip-stripped-log' into 'main'
remove apricorn_stripped_log and apricorn_stripped_log_top as never used

See merge request cable-mc/cobblemon!1502
2025-01-31 07:27:54 +00:00
gbassinello 22b4e8c75f chore: changelog lines 2025-01-31 01:44:50 -03:00
gbassinello c19a3ca444 feat: set winners and losers on battle end 2025-01-31 01:44:50 -03:00
Polymetaandgbassinello a006eb5dcc revert previous attempt and fix camera mode
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-01-31 01:44:50 -03:00
gbassinello ed419e7e53 fix: removing activeDialogues from the DialogueManager map using the correct key (player uuid) 2025-01-31 01:44:50 -03:00
Hiroku bff2387b4d Merge branch 'feature/particle-fixes' into 'main'
revert previous attempt and fix camera mode

See merge request cable-mc/cobblemon!1506
2025-01-31 04:02:00 +00:00
Polymeta 41544efeba revert previous attempt and fix camera mode
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-01-30 23:15:08 +00:00
Paul e6e6c9f7f6 Merge remote-tracking branch 'origin/main' 2025-01-31 08:31:31 +10:00
Paul 22d8e39db3 back to snapshots 2025-01-31 08:31:17 +10:00
Hiroku bfdf1e9e6c Merge branch 'fix-activedialoguesmapkey' into 'main'
fix: removing activeDialogues from the DialogueManager map using the correct key (player uuid)

Closes #1405

See merge request cable-mc/cobblemon!1503
2025-01-30 22:19:22 +00:00
BuildTools c3fccfde09 Fix PC opening on Box 2 because default value for 'box' in OpenPCPacket was '1' instead of '0' 2025-01-30 21:48:18 +02:00
gbassinello 4bb8d43a6e fix: calling setPages() when initializing the dialogue so default pages can have their timeout scheduled 2025-01-30 13:50:18 -03:00
gbassinello fda4b67776 fix: removing activeDialogues from the DialogueManager map using the correct key (player uuid) 2025-01-30 13:34:52 -03:00
Xander Forrest f1ee9d45de remove apricorn_stripped_log and apricorn_stripped_log_top as never used 2025-01-28 19:39:28 +00:00
Polymeta 01f7d13e3f update tag and preset list [skip-ci]
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-01-26 21:32:32 +00:00
Paul d85e30f3a6 But what if we didn't break the yarn mapping 2025-01-26 22:15:17 +10:00
Paul e6f147bd94 Changelog [skip-ci] 2025-01-26 09:34:42 +10:00
Paul c66de51e39 Snapnoshot 2025-01-26 08:53:26 +10:00
Hiroku 7d552735f3 Merge branch 'implement_pokemon' into 'main'
Wobbuffix (and charcadet)

See merge request cable-mc/cobblemon!1500
2025-01-25 22:32:19 +00:00
Carmendar 94c42e7e2c Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-01-25 16:27:21 -06:00
Carmendar ef4690d4fe Wobbuffet -w- 2025-01-25 16:26:48 -06:00
Polymeta 433c0ff345 Merge remote-tracking branch 'refs/remotes/origin/lang-updates' 2025-01-25 21:00:42 +00:00
FrankTheFarmer 59d42fb328 Updated Charcadet's eye height. Git being dumb 2025-01-26 06:19:18 +10:00
Gustavo PuerariandWeblate 17d6837e34 Translated using Weblate (Portuguese (Brazil))
Currently translated at 42.1% (2695 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2025-01-25 10:01:29 +00:00
Carmendar 34b4337849 Updated Eiscue Noice lang 2025-01-25 03:14:00 -06:00
Paul 392e8663be Merge remote-tracking branch 'origin/main' 2025-01-25 14:29:28 +10:00
Paul 578ff37705 More tweaks to bucket jumps for luck of the sea enchants 2025-01-25 14:29:18 +10:00
Hiroku 77406f91a3 Merge branch '1.6.1-spawns' into 'main'
Fixes to some spawns and tags.

See merge request cable-mc/cobblemon!1498
2025-01-25 02:08:20 +00:00
Polymeta 9bf526e93e deleted typo'd amoonguss file
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-01-25 02:00:33 +00:00
Veraxiel 29b763ef19 Updated spawns and tags. 2025-01-24 20:40:50 -05:00
Polymeta 938b7a7a94 flip UVs to make particle sprite point the other direction
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-01-25 01:38:00 +00:00
Paul f920639e3f Protect luck of the sea adjustments against custom buckets 2025-01-25 11:35:10 +10:00
Paul ea499a935e Updated fishing bucket rates 2025-01-25 11:02:58 +10:00
Hiroku 1dbe5eb944 Merge branch 'npc-hide-nametag' into 'main'
Added hideNameTag field for NPCs

See merge request cable-mc/cobblemon!1488
2025-01-25 00:47:59 +00:00
Paul dba0bae810 Corrected luck of the sea bucket weights and simplified calculation code 2025-01-25 10:37:19 +10:00
Paul 8c04081af5 Fixed uncaught exception from fishing reeling in blocked entity spawns 2025-01-25 10:00:50 +10:00
Hiroku d7de4b2463 Merge branch 'test/fix_targeting_variant' into 'main'
Fix default form in battle targeting

Closes #1376

See merge request cable-mc/cobblemon!1496
2025-01-24 22:58:15 +00:00
aeroeng15andHiroku 61b767158a Fix default form in battle targeting 2025-01-24 22:58:15 +00:00
Hiroku f2f16cdc9e Merge branch 'implement_pokemon' into 'main'
Merge implement into main

See merge request cable-mc/cobblemon!1497
2025-01-24 22:57:45 +00:00
Deltric 2aec4f972f Updated npc name tag hiding to allow individual entity based hiding. 2025-01-24 04:23:02 -06:00
Deltric bc8164cf17 Merge remote-tracking branch 'origin/npc-hide-nametag' into npc-hide-nametag 2025-01-24 04:22:09 -06:00
Deltric a09cf1b93d Updated NPC README.md with hideNameTag field. 2025-01-24 04:11:29 -06:00
Deltric b436c42cb1 Hide name tag field for NPCs 2025-01-24 04:11:29 -06:00
Polymeta 79b83bc8d7 Merge branch 'test/held_item_evos' into 'main'
Fix held items disappearing for evolutions on re-logs

Closes #1378

See merge request cable-mc/cobblemon!1495
2025-01-24 08:22:25 +00:00
aeroeng15andPolymeta a6b5453b34 Fix held items disappearing for evolutions on re-logs 2025-01-24 08:22:25 +00:00
Carmendar 7fcb9e8b4d Riolu can stare into your soul, Charizard now uses all of his quirks, Corphish & Crawdaunt no longer T-pose. 2025-01-24 02:19:37 -06:00
Hiroku f3740abd39 Merge branch 'sound-packet-updates' into 'main'
Updated UnvalidatedPlaySoundS2CPacket to be public instead of internal and made its fields mutable.

See merge request cable-mc/cobblemon!1494
2025-01-24 06:54:55 +00:00
Hiroku e4decf50ea Merge branch 'spawn-packet-updates' into 'main'
Updated spawn packet visibility and mutability for Pokemon & NPCs

See merge request cable-mc/cobblemon!1489
2025-01-24 04:47:30 +00:00
Hiroku 22d33ac5d8 Merge branch '#1377-npc-held-items-bug' into 'main'
[#1377] Fixed held items being stolen from NPCs

Closes #1377

See merge request cable-mc/cobblemon!1490
2025-01-24 04:46:48 +00:00
DeltricandHiroku f2392db3be [#1377] Fixed held items being stolen from NPCs 2025-01-24 04:46:48 +00:00
Hiroku 9fed44328f Merge branch '#1374-fix-evolution-mid-battle' into 'main'
[#1374] Fixed Pokémon being able to evolve mid-battle

Closes #1374

See merge request cable-mc/cobblemon!1491
2025-01-24 04:46:36 +00:00
Hiroku 26d0340fb5 Merge branch 'sterr/sounds' into 'main'
Sound fixes

See merge request cable-mc/cobblemon!1493
2025-01-24 04:45:06 +00:00
Gustavo PuerariandWeblate 21f2945dc4 Translated using Weblate (Portuguese (Brazil))
Currently translated at 41.4% (2648 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2025-01-24 04:01:50 +00:00
Deltric 16a5316a69 Updated UnvalidatedPlaySoundS2CPacket to be public instead of internal and made its fields mutable. 2025-01-23 19:02:14 -06:00
Deltric 378a5ca401 Update evolution handler to disallow evolving while player is in battle. 2025-01-23 17:01:21 -06:00
Konoha d956ca2c3c Re-prep Inkay Easter Egg Evos :) 2025-01-23 17:25:35 -05:00
Guilherme Pereira 49d7129950 Merge branch 'means-of-transportation' of gitlab.com:cable-mc/cobblemon into means-of-transportation 2025-01-23 18:50:52 -03:00
Guilherme Pereira da46d71280 add configurable DABR controls for ride controllers 2025-01-23 18:50:23 -03:00
Deltric 14a079fae1 Updated NPC README.md with hideNameTag field. 2025-01-23 15:44:47 -06:00
Sterrezo 3e9331ec64 Updated the evolution sound to match the particle effect timing better 2025-01-23 22:34:19 +01:00
Sterrezo a7c43701c0 Wild shiny sounds now respect the shinyNoticeParticlesDistance config setting 2025-01-23 22:12:13 +01:00
JPAK e44eb3f77f Fix rotations and player positioning on the ground. 2025-01-23 13:46:30 -06:00
Kenji_64 34aef306c1 Fixed shiny Flygon's goggles texture 2025-01-23 20:07:47 +01:00
Deltric b4e99204c8 Fixed Pokémon being able to evolve mid-battle 2025-01-23 03:21:04 -06:00
Guilherme Pereira 6027934c22 add glider air controller 2025-01-23 05:17:37 -03:00
Deltric 8c09cebc59 Updated spawn packet visibility and mutability for Pokemon & NPCs 2025-01-23 01:54:48 -06:00
Deltric b5bfe44196 Hide name tag field for NPCs 2025-01-23 01:45:58 -06:00
Carmendar 38c5fcc23f Applied gravity to Arctozolt profile 2025-01-22 21:51:15 -06:00
Carmendar 9edfa279be Lucario can finally look at your aura. (can turn head) 2025-01-22 21:18:24 -06:00
Carmendar 2769d5560d Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-01-22 21:02:43 -06:00
Carmendar ed7d2d5d2a Hitbox fixes for Eiscue and Golem. 2025-01-22 21:02:09 -06:00
Kenji_64 3b96beef36 Adjustments for Krokorok's/Krookodile's sand walk speed 2025-01-23 00:03:27 +01:00
Kenji_64 dcbac52fd7 Some Seaking animation and walk speed edits 2025-01-22 23:52:30 +01:00
Kenji_64 64dd8336c6 Made Krookodile's/Krokorok's look quirk rarer 2025-01-22 23:52:08 +01:00
washashu0905andWeblate b430b8a1b4 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 79.6% (5091 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-01-22 01:05:35 +00:00
TeggyandWeblate 329810407a Translated using Weblate (Spanish)
Currently translated at 100.0% (6391 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es/
2025-01-22 01:05:33 +00:00
Konoha a71cfaadc8 Toggleable Mooshtank var. in dex
Also stubs unimplemented branch regional evolutions (Avalugg/Weezing/Mr. Mime) + biome fix to fix chat spam in nether during night.
2025-01-21 11:17:02 -05:00
Konoha 31195dacdb Resolve invalid Molang expression for Golem sleep anim 2025-01-21 09:57:35 -05:00
Polymeta 4074aa50ce refactor storage layer and introduce .old filetype as a stopgap for file corruption during crashes
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-01-21 02:14:35 +00:00
Konoha 107ec7634d Temp-Swap Unsupported Evo Item References & Sidemod Tutor Support
Temporarily exchanges items that aren't in Cobblemon referenced on some species with items that are, avoiding the crash that would occur when Bisharp's evolution was parsed.
Adds a new utility script to mass-manage TM/Tutor moves from the movepool.
Reintroduces the "tutor" subset of TMs for addons that utilize the source already.
More aggressive culling on unplanned base-mod TM moves from level/egg pools, this prevents breakage with addons using the "lazy" way of only pulling the source in species data. Doing this will eventually break custom TMs in the TMM, so it is recommended that addons/plugins migrate to global lists of TMs for interfacing moves instead of just pulling "tm:" for each species.
Also re-preps the aspect format for Keldeo's species feature to match others.
2025-01-20 16:16:28 -05:00
GenotypeXD-Dev b5694b4e13 Palm tree texture fix 2025-01-19 16:18:56 -07:00
GenotypeXD-Dev 9df4669865 Oops animations and model didnt push 2025-01-19 16:14:16 -07:00
GenotypeXD-Dev 92543f9aed Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-01-19 16:13:17 -07:00
GenotypeXD-Dev 5d5cb3a240 Implement Alolan Exeggutor Remodel 2025-01-19 16:13:07 -07:00
Konoha bc267ec72b Correct "Undiscovered" form oversight with data tag culling
This only affects the 3 forms who are in the undiscovered group and had accidentally inherited the base form's egg groups during the culling script's comparison, and did not have handling for their "legacy" movesets not totally covered by newer games.
2025-01-19 17:09:33 -05:00
Kenji_64 6d89b737a7 Added flame animations to Charcadet 2025-01-19 21:02:53 +01:00
Kenji_64 53e540472a Fixed Eiscue's scale (1 -> 0.85) 2025-01-19 21:02:33 +01:00
Konoha e2804dc83f Reimplement non-Torterra wood choices to Cobblemon Tree feature. 2025-01-19 09:53:16 -05:00
TeggyandWeblate 82e82cb28e Translated using Weblate (Spanish)
Currently translated at 99.3% (6350 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es/
2025-01-19 05:07:47 +00:00
JPAK 608d004a9c Player now rolls, and sits on the seat correctly. Positioning the camera needs work still. 2025-01-18 20:32:34 -06:00
JPAK 2e532af5d2 Debug bools for testing hitboxes without camera/pokemon rolling. 2025-01-12 19:34:23 -06:00
Paul b1352db5c5 Fixed some bugs with the bird air controller and allowed wing flapping 2025-01-13 11:02:50 +10:00
apion 4df6233994 Added HelicopterAirController, allows for creative-like up and down movement 2025-01-12 20:01:50 -05:00
Paul 515d04c17c Conflicto fixo (AND LICENSES!!!11!one!) 2025-01-13 09:26:22 +10:00
Paul 81c5f9ce24 Merge remote-tracking branch 'origin/main' into flying-mount-prototype
# Conflicts:
#	common/src/main/java/com/cobblemon/mod/common/mixin/MouseHandlerMixin.java
#	common/src/main/java/com/cobblemon/mod/common/mixin/PlayerMixin.java
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonNetwork.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/events/CobblemonEvents.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/pokemon/PokemonRenderer.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/PokemonEntity.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/pokemon/FormData.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/pokemon/Species.kt
#	common/src/main/resources/assets/cobblemon/lang/en_us.json
#	common/src/main/resources/mixins.cobblemon-common.json
2025-01-13 08:57:25 +10:00
Paul d8cd1a6288 Merge remote-tracking branch 'origin/means-of-transportation' into flying-mount-prototype 2025-01-13 08:38:13 +10:00
JPAK cb4e331c29 Rotate the seat for the player based on the orientation of the first passenger. This currently pivots around (0,0) of the riding entity, IE the bottom center of the hitbox. 2024-10-27 22:36:39 -05:00
Landon Wills 18138c8374 Start synchronization of player orientation to server 2024-10-26 16:11:28 -04:00
Landon Wills 6280fd5420 Hello code-changes lurkers 2024-10-13 00:20:34 -04:00
Landon Wills b25271bf22 Fix rotation logic 2024-10-12 16:18:16 -04:00
Landon Wills 1b530a511b Update camera logic 2024-10-12 14:35:20 -04:00
Landon Wills 90791097f1 Add beginnings of camera tomfoolery 2024-10-11 20:45:21 -04:00
Paul 0b1c15bca8 Conflicto 2024-10-11 14:17:27 +10:00
Paul b490831944 Merge remote-tracking branch 'origin/main' into means-of-transportation
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/PokemonEntity.kt
2024-10-11 14:16:16 +10:00
Paul d16e22c27d Further refinement to riding with state and composite controllers 2024-10-06 16:51:18 +10:00
Paul 892d9e78e9 Merge remote-tracking branch 'origin/main' into means-of-transportation
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/api/events/CobblemonEvents.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/PokemonEntity.kt
#	common/src/main/resources/assets/cobblemon/lang/en_us.json
#	common/src/main/resources/mixins.cobblemon-common.json
2024-10-05 18:53:59 +10:00
Paul dfeae8031b Mappings conversions 2024-08-31 14:01:41 +10:00
Paul 53168aa4cb Merge remote-tracking branch 'origin/sega_bass_pro_fishing_2' into means-of-transportation
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/Cobblemon.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/snowstorm/BedrockParticle.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/gui/interact/wheel/InteractWheelGuiFactory.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/net/gui/InteractPokemonUIPacketHandler.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/block/DisplayCaseRenderer.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/PokemonEntity.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/net/messages/client/ui/InteractPokemonUIPacket.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/net/messages/server/pokemon/interact/InteractPokemonPacket.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/pokemon/Pokemon.kt
2024-08-31 12:28:55 +10:00
Paul a280fc5930 Merge branch 'refs/heads/sega_bass_pro_fishing_2' into means-of-transportation
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/PokemonEntity.kt
2024-06-23 09:07:40 +10:00
Paul 4d6744549c Merged in the fishing branch so we're 1.20.6 here now cool thx 2024-06-14 20:45:28 +10:00
Paul 1c14f3261d Merge branch 'refs/heads/sega_bass_pro_fishing_2' into means-of-transportation
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonNetwork.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/molang/MoLangFunctions.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/net/serializers/StringSetDataSerializer.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/reference/Reference.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/battles/BattleBuilder.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/CobblemonClient.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/gui/dialogue/RenderableFace.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/particle/ParticleStorm.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/generic/GenericBedrockRenderer.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/PosableState.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/PoseableEntityModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/bedrock/animation/BedrockAnimation.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/npc/PosableNPCModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/repository/NPCModelRepository.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/npc/NPCRenderer.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/pokeball/PokeBallRenderer.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/pokemon/PokemonRenderer.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/command/TestCommand.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/generic/GenericBedrockEntity.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/npc/NPCEntity.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/pokeball/EmptyPokeBallEntity.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/PokemonEntity.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/item/interactive/PokerodItem.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/util/MiscUtils.kt
#	common/src/main/resources/cobblemon-common.accesswidener
#	deps/local/com/bedrockk/molang/maven-metadata-local.xml
#	fabric/src/main/kotlin/com/cobblemon/mod/fabric/client/CobblemonFabricClient.kt
#	gradle/libs.versions.toml
2024-06-14 15:13:36 +10:00
Paul 6fb38fc70c Correction 2024-06-14 15:12:48 +10:00
Paul 3f04102990 Merge branch 'refs/heads/1.20.5' into means-of-transportation
# Conflicts:
#	common/build.gradle.kts
#	common/src/main/kotlin/com/cobblemon/mod/common/Cobblemon.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonNetwork.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/molang/MoLangFunctions.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/net/serializers/StringSetDataSerializer.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/battles/BattleBuilder.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/CobblemonClient.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/gui/dialogue/RenderableFace.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/particle/ParticleStorm.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/block/DisplayCaseRenderer.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/PoseableEntityModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen5/ConkeldurrModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen5/GolettModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen5/GolurkModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/generic/GenericBedrockEntity.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/pokeball/EmptyPokeBallEntity.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/PokemonEntity.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/net/messages/client/animation/PlayPosableAnimationPacket.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/net/messages/client/ui/InteractPokemonUIPacket.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/net/messages/server/pokemon/interact/InteractPokemonPacket.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/pokemon/FormData.kt
#	common/src/main/resources/cobblemon-common.accesswidener
#	fabric/src/main/kotlin/com/cobblemon/mod/fabric/client/CobblemonFabricClient.kt
#	gradle.properties
2024-06-14 14:50:47 +10:00
Nick 28cbc0a6fa Adjustments for driver selection, fixes NPE 2024-06-02 23:53:29 -07:00
Nick 5c74fabdc6 Add new event for driver selection 2024-06-02 22:25:21 -07:00
Nick ab53a2cad4 Merge remote-tracking branch 'origin/means-of-transportation' into means-of-transportation
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/api/riding/seats/Seat.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/PokemonEntity.kt
2024-06-02 21:30:50 -07:00
Paul 14b3e84b77 Riding seat rework, render players at seat locators where they exist 2024-06-03 14:26:48 +10:00
Nick a629a59654 Merge remote-tracking branch 'origin/means-of-transportation' into means-of-transportation
# Conflicts:
#	common/build.gradle.kts
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/PokemonEntity.kt
2024-06-02 00:16:24 -07:00
Paul d51c91cb5a Handled jumping and molang and blackjack for land controller 2024-06-02 13:19:40 +10:00
Paul 706bf65664 Merge branch 'refs/heads/no-entity-rendering' into means-of-transportation
# Conflicts:
#	build-logic/settings.gradle.kts
#	common/build.gradle.kts
#	common/src/main/kotlin/com/cobblemon/mod/common/Cobblemon.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/PoseableEntityModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/animation/SingleBoneLookAnimation.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/PokemonEntity.kt
#	fabric/src/main/kotlin/com/cobblemon/mod/fabric/client/CobblemonFabricClient.kt
#	gradle/build-logic/src/main/kotlin/utilities/Git.kt
#	gradle/libs.versions.yml
#	gradle/wrapper/gradle-wrapper.properties
#	settings.gradle.kts
2024-06-01 19:47:06 +10:00
Paul 6394c6d686 Merge remote-tracking branch 'origin/means-of-transportation' into means-of-transportation 2024-06-01 19:14:54 +10:00
Paul 145a8904c2 Why am I not getting compiler errors when there are compile errors dude just give me the danger squiggles 2024-06-01 18:28:56 +10:00
Paul eba400a6ec I will destroy the license with my mind lasers 2024-06-01 16:29:14 +10:00
Paul 12626e2d26 Major refactors and renames for animation system, documented the heck out of it all 2024-06-01 16:06:55 +10:00
Paul c044ff6d8b Conflicto patronum 2024-06-01 10:12:35 +10:00
Paul 33465b1d9e Merge branch 'refs/heads/sega_bass_pro_fishing_2' into no-entity-rendering
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/battles/interpreter/instructions/MoveInstruction.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/block/chest/GildedChestBlock.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/particle/ParticleStorm.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/block/RestorationTankRenderer.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/PoseableEntityModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/JsonPokemonPoseableModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/PidgeyModel.kt
2024-06-01 09:46:27 +10:00
Paul dbea41cbf4 MoLang refactors for optimizations, migrate to PokemonPosableModel subclass, fixes, do pose transitions from ticking so they still transition when off-screen 2024-05-31 17:05:49 +10:00
Paul 8cab5b17f7 Huge amounts of refactoring in animation code, still need to figure out aspects from PosableState 2024-05-26 21:06:57 +10:00
Paul 3c86d13b44 A lot of error resolution from giga merge 2024-05-24 20:31:22 +10:00
Paul a9a4cc8788 Merge remote-tracking branch 'origin/sega_bass_pro_fishing_2' into no-entity-rendering
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonNetwork.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonSounds.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/gui/GuiUtils.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/moves/animations/keyframes/AnimationActionEffectKeyframe.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/moves/animations/keyframes/EntityMoLangActionEffectKeyframe.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/moves/animations/keyframes/EntityParticlesActionEffectKeyframe.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/moves/animations/keyframes/EntitySoundActionEffectKeyframe.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/moves/animations/keyframes/MoLangActionEffectKeyframe.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/moves/animations/keyframes/PauseActionEffectKeyframe.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/moves/animations/keyframes/RemoveHoldsActionEffectKeyframe.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/moves/animations/keyframes/ReturnToPositionActionEffectKeyframe.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/spawning/detail/NPCSpawnAction.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/battles/ShowdownInterpreter.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/battles/interpreter/instructions/DamageInstruction.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/CobblemonClient.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/entity/EmptyPokeBallClientDelegate.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/entity/PokemonClientDelegate.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/net/effect/RunPosableMoLangHandler.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/JsonPose.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/PosableState.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/PoseableEntityModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/animation/PrimaryAnimation.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/animation/SingleBoneLookAnimation.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/bedrock/animation/BedrockAnimation.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/fossil/FossilModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/frame/HeadedFrame.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/JsonPokemonPoseableModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/AerodactylModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/ArcanineModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/ChanseyModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/CharizardModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/CuboneModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/DewgongModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/DiglettModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/DodrioModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/DoduoModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/DragonairModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/DragoniteModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/DratiniModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/DugtrioModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/ElectabuzzModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/ElectrodeModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/ExeggutorModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/GeodudeModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/GolbatModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/GolemModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/GravelerModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/GrimerModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/GrowlitheModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/KabutoModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/KabutopsModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/KinglerModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/KoffingModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/KrabbyModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/LaprasModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/MagikarpModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/MarowakModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/MeowthAlolanModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/MeowthGalarianModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/MeowthModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/MukModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/NidoranfModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/NinetalesModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/OmanyteModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/OmastarModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/PidgeotModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/PidgeyModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/PinsirModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/PsyduckModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/RapidashGalarianModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/ScytherModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/SeelModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/SnorlaxModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/SquirtleModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/TangelaModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/TentacoolModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/TentacruelModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/VenomothModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/VenonatModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/VoltorbModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/VulpixModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/WartortleModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/WeezingModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen2/BlisseyModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen2/ChinchouModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen2/DonphanModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen2/ElekidModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen2/FlaaffyModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen2/GligarModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen2/GranbullModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen2/IgglybuffModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen2/LanturnModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen2/NatuModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen2/PhanpyModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen2/PiloswineModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen2/SneaselModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen2/SwinubModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen2/XatuModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen2/YanmaModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen3/BarboachModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen3/CacneaModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen3/CacturneModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen3/ChimechoModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen3/GardevoirModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen3/GrovyleModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen3/IllumiseModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen3/KirliaModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen3/MawileModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen3/MightyenaModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen3/NumelModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen3/RaltsModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen3/SceptileModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen3/TorkoalModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen3/TreeckoModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen3/VolbeatModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen3/WhiscashModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen3/ZigzagoonGalarianModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen4/BibarelModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen4/BidoofModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen4/BuizelModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen4/CarnivineModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen4/ChinglingModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen4/DrifblimModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen4/DrifloonModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen4/DusknoirModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen4/ElectivireModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen4/FloatzelModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen4/GabiteModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen4/GalladeModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen4/GarchompModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen4/GibleModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen4/GliscorModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen4/HappinyModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen4/LucarioModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen4/MamoswineModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen4/TangrowthModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen4/WeavileModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen4/YanmegaModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen5/BasculinModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen5/BouffalantModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen5/ChandelureModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen5/ConkeldurrModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen5/GurdurrModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen5/KlangModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen5/KlinkModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen5/KlinklangModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen5/LampentModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen5/LitwickModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen5/OshawottModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen5/RoggenrolaModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen5/SamurottModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen5/SigilyphModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen5/TimburrModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen6/PumpkabooModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen6/ScatterbugModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen7/CutieflyModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen7/KomalaModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen8/CentiskorchModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen8/FalinksModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen8/ObstagoonModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen8/RabootModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen8/SizzlipedeModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen9/CharcadetModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen9/GholdengoModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen9/GimmighoulChestModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen9/GimmighoulRoamingModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen9/LechonkModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen9/MausholdModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen9/MausholdfourModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen9/OinkologneMaleModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen9/QuaquavalModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/pokemon/PokemonRenderer.kt
#	common/src/main/resources/assets/cobblemon/sounds.json
#	deps/local/com/bedrockk/molang/1.1.12/molang-1.1.12.pom
2024-05-24 19:35:12 +10:00
Nick a512a99fb2 Merge branch 'main' of gitlab.com:cable-mc/pokemon-cobbled into means-of-transportation
# Conflicts:
#	build-logic/settings.gradle.kts
#	common/build.gradle.kts
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/PokemonEntity.kt
#	gradle/build-logic/src/main/kotlin/utilities/Git.kt
#	gradle/libs.versions.yml
#	gradle/wrapper/gradle-wrapper.properties
#	settings.gradle.kts
2024-05-18 12:04:34 -07:00
Nick 03a63e8310 Big main sync 2024-05-11 11:19:12 -07:00
Paul 0261df0f06 Toying around with jump controls on ride controllers 2024-05-10 09:44:56 +10:00
Paul a035ee7856 Some cleanup and fixes to land movement 2024-05-05 10:02:49 +10:00
Paul 6cf94307d3 Introducing molang to generic land controller 2024-05-04 22:25:36 +10:00
Paul 98bd827862 Merge remote-tracking branch 'origin/main' into means-of-transportation 2024-05-02 09:54:14 +10:00
Paul 86b49d5b1b Reworked ride controller serialization, scrubbed old properties and made ride jumping exist again 2024-04-30 12:39:03 +10:00
Paul a51f1e5ff9 Merge remote-tracking branch 'origin/means-of-transportation' into means-of-transportation
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/api/riding/controller/RideController.kt
2024-04-30 10:36:22 +10:00
Nick 3307bedf08 Add basic enough conditions to liquid controllers, allow them to run 2024-04-28 23:56:00 -07:00
Nick 4bf3bf07e4 Goodbye capabilities 2024-04-28 23:37:14 -07:00
Paul 9c0647d656 Little logging to help me understand jumps 2024-04-29 13:30:01 +10:00
Paul 3b53035935 Merge remote-tracking branch 'origin/main' into means-of-transportation
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/PokemonServerDelegate.kt
2024-04-29 11:28:39 +10:00
Paul 22730cd452 Fixed land capability no worky 2024-04-29 11:00:15 +10:00
Paul da8d495a30 Merge remote-tracking branch 'origin/means-of-transportation' into means-of-transportation 2024-04-28 15:51:54 +10:00
Nick 6ea5a1f7ce Cleanup + don't defer render if in fabulous 2024-04-27 22:46:34 -07:00
Paul 5757b9c69e Merge remote-tracking branch 'origin/means-of-transportation' into means-of-transportation 2024-04-28 13:50:24 +10:00
Paul 3533181c91 Merge remote-tracking branch 'origin/main' into means-of-transportation
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/Cobblemon.kt
2024-04-28 13:47:13 +10:00
amo cb9cd76a15 fix translucent pokemon layering 2024-04-28 00:08:24 +01:00
Nick 6effa13dfb Work towards opacity on ridden models 2024-04-27 15:22:47 -07:00
Nick 5e78f89935 We're just going to claim stuff for this one 2024-04-26 21:01:49 -07:00
Nick 5a5442f666 Main sync 2024-04-19 19:01:30 -07:00
Paul 6d119dd9d4 Conflicts and corrections 2024-03-01 12:57:02 +10:00
Paul 32bd21eb04 Conflicts 2024-03-01 11:52:30 +10:00
apion 8d495a4be0 Made capabillity predicates a little bit more accurate 2024-02-14 19:13:09 -05:00
Nick d7069904c7 Better checks for capabilities, transitions now working between land and water 2024-02-10 23:05:04 -08:00
Nick 3d48324a43 Begin work on liquid capabilities for mounts 2024-02-05 18:00:50 -08:00
Paul 143dedaa06 Finished removing all generics from the model system 2024-01-28 10:44:37 +10:00
Paul b8fe170f19 Merge branch 'npcs' into no-entity-rendering
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/api/gui/GuiUtils.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/entity/PokemonClientDelegate.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/gui/dialogue/RenderableFace.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/PosableState.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/PoseableEntityModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/animation/BimanualSwingAnimation.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/animation/BipedWalkAnimation.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/animation/PrimaryAnimation.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/animation/QuadrupedWalkAnimation.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/animation/SingleBoneLookAnimation.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/animation/WingFlapIdleAnimation.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/bedrock/animation/BedrockAnimation.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/bedrock/animation/BedrockStatefulAnimation.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/bedrock/animation/BedrockStatelessAnimation.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/JsonPokemonPoseableModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/PokemonPoseableModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/BlastoiseModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen1/CharizardModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pokemon/gen4/GalladeModel.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/pose/Pose.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/quirk/ModelQuirk.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/quirk/QuirkData.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/quirk/SimpleQuirk.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/quirk/SimpleQuirkData.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/models/blockbench/repository/FossilModelRepository.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/Poseable.kt
2024-01-27 11:22:08 +10:00
Nick a02261fcac Adjust max block speed/tick and dummy solution for movement state 2024-01-25 07:56:22 -08:00
Nick 996bf3f929 Sync properties to client, working demo of riding 2024-01-24 23:23:43 -08:00
Nick 8449aff799 Merge branch 'main' of gitlab.com:cable-mc/pokemon-cobbled into means-of-transportation 2024-01-23 19:07:09 -08:00
Nick 80df79f93a Sync properly with latest main 2024-01-15 23:58:11 -08:00
Nick 897419a0b6 Decently large restructure of riding design, not fully linked up just yet 2024-01-15 23:13:00 -08:00
Paul 255dd5d974 Started rework of PoseableEntityModel 2024-01-05 19:55:04 +10:00
Nick c45085a520 Latest code towards riding 2023-10-23 22:15:31 -07:00
Nick 16bc881110 Blossom integration, crash report info details and API adjustments for riding design 2023-09-16 23:08:09 -07:00
Nick 0086d30755 Updates towards design 2023-09-07 20:49:16 -07:00
Nick 1170a61b81 Fix merge compilation errors 2023-09-05 23:05:06 -07:00
Nick 066013a9bd License 2023-09-05 22:30:40 -07:00
Nick 931e0b2613 Main sync 2023-09-05 21:53:33 -07:00
Nick f49409e021 Established speed and acceleration formulas to additionally calculate momentum per active tick 2023-08-19 02:17:26 -07:00
Nick 29eeebd178 Clean up API design, refactor momentum calculation design 2023-08-13 13:47:04 -07:00
Nick 50447b6d77 Fix compilation errors + riding positions 2023-08-12 18:10:14 -07:00
Nick 0b977cce84 Merge remote-tracking branch 'remotes/origin/main' into means-of-transportation 2023-08-12 17:42:55 -07:00
Nick 02f62896b0 Apply merge with origin 2023-08-05 12:04:05 -07:00
Nick 1535ba5cb5 Merge with latest main 2023-08-05 12:00:50 -07:00
Paul baccb9a9a1 Compat 1.20.1 2023-07-25 22:18:50 +10:00
Paul 50454ac2db Merge remote-tracking branch 'origin/main' into means-of-transportation
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/api/pokemon/PokemonSpecies.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/gui/interact/pokemon/PokemonInteractGUI.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/net/gui/InteractPokemonUIPacketHandler.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/PokemonEntity.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/net/serverhandling/pokemon/interact/InteractPokemonHandler.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/pokemon/FormData.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/pokemon/Pokemon.kt
#	common/src/main/resources/mixins.cobblemon-common.json
#	gradle.properties
2023-07-25 21:50:06 +10:00
Nick 574c9eb36b Begin working on riding traits (Tremendously experimental) 2023-06-06 20:46:09 -07:00
Nick bc75d3331f Begin work on jumping mounts + handle dismounting of riders when submerged underwater 2023-05-27 23:58:55 -07:00
Nick 950e683b45 Remove the no longer needed todo, we did it 2023-05-26 20:38:21 -07:00
Nick a010d97e51 Base riding design complete, now the fun begins... I hate you SPG 2023-05-26 20:31:45 -07:00
Nick bdb9a7e396 Work towards riding API and Implementation 2023-05-17 21:59:37 -07:00
1186 changed files with 34983 additions and 14959 deletions
+97 -58
View File
@@ -1,20 +1,28 @@
# Changelog
## [1.6.1 (Release TBD)](#1-6-1)
## [1.7.0 (Month xth, 2025)](#1-7-0)
### Fixes
- Fixed Particles sometimes facing the wrong direction (looking at you, Swords Dance)
- Fixed PCs always opening at box 2 instead of box 1.
### Developer
- A finished battle now has winners and losers set inside of `PokemonBattle` instead of them always being empty.
- Dialogues are correctly removed from memory when they are stopped.
- Dialogues with variably-set initial pages now properly start timeout tracking.
## [1.6.1 (January 26th, 2025)](#1-6-1)
### Additions
- Added config setting `maxPokedexScanningDetectionRange` to control from what distance the player can scan Pokémon using the Pokédex.
- Added the `is_standing_on_blocks(depth, blocks...)` MoLang function, which returns whether the specified entity is standing on a specific block or set of blocks. Example usage: `q.is_standing_on_blocks(2, minecraft:sand)`
- Added config setting `hideUnimplementedPokemonInThePokedex` which hides unimplemented Pokémon from the Pokédex when set to true.
- Added molang particle queries for getting distance to targeted entities.
- Added debug renderer for poseable entity locators.
- Added `baseScale` property to NPCs.
- Added cry for Spinda.
- Added the player to `PokerodReelEvent`.
- Pokédex and Dialogue API screens now close when the inventory keybind is pressed.
- Added Galarica Nuts, used for crafting Galarica Cuffs and Wreaths. Dropped from certain Pokémon.
- Added specific compatibility with Repurposed Structures. (Thank you, TelepathicGrunt!)
- Added an evolution method for Karrablast to evolve into Escavalier in single-player mode.
- Added crossover paintings from Close Combat: Premonition, Altar, Slumber, and Nomad.
- Added Galarica Nuts, used for crafting Galarica Cuffs and Wreaths. Dropped from certain Pokémon. Take a wild guess which.
- Added compatibility with Repurposed Structures. (Thank you, TelepathicGrunt!)
- Added an evolution method for Karrablast to evolve into Escavalier in singleplayer.
- Pokédexes can now be placed in Chiseled Bookshelves.
- Added optional box argument to the /pc command.
- Pokédex and Dialogue screens now close when the inventory keybind is pressed.
- Added config setting `maxPokedexScanningDetectionRange` to control from what distance the player can scan Pokémon using the Pokédex.
- Added config setting `hideUnimplementedPokemonInThePokedex` which hides unimplemented Pokémon from the Pokédex when set to true.
- Added debug renderer for posable entity locators.
- Added crossover paintings from Close Combat, Premonition, Altar, Slumber, and Nomad.
- Added optional box argument to the /pc command
@@ -30,6 +38,7 @@
- New Slowpoke shiny texture.
- Updated drops for many Pokémon.
- Completely resynced Pokémon move and stat data based on later games. Learnsets have changed considerably to maximise available moves.
- Cobblemon save data now saves .old files where applicable as a means to recover from file corruption due to crashes or similar abrupt stops
### Pokémon Added
@@ -62,7 +71,7 @@
- Galarian Slowking
#### Gen 9
- Paldean Tauros's
- Paldean Tauros
### Added cries to the following Pokémon
- All Nidorans
@@ -73,7 +82,7 @@
### Animation updates for the following Pokémon
- Primeape
- Munchlax
- Munchlax
- Snorlax
- Poliwrath
- Goldeen
@@ -109,35 +118,46 @@
### Cry updates for the following Pokémon
- Sceptile
### Changes
- Completely re-synced Pokémon move and stat data based on later games. Learnsets have changed considerably to maximise available moves.
- Pokémon will now be dynamically revealed to the Pokédex as they're seen in battle instead of revealing entire parties at the end of battle.
- Unseen wild Pokémon will update their name from '???' to their real name as soon as a battle starts to match how the battle UI shows the actual species name.
- Pokémon under the illusion effect will reveal their disguise to the Pokédex first and then the base Pokémon once the disguise is broken.
- Berries will now drop from berry trees if broken at age 0 so you aren't punished for mistaken planting.
- Increased Fortune drops on Mint Seeds.
- Updated Slowpoke's shiny texture.
- Updated drops for many Pokémon.
- Adjusted the evolution sound to match the timing of the particle effect.
- Made berry trees shear-able by dispenser blocks. I'm sure nobody will make unholy contraptions with this.
- Edited some recipes to utilize tags instead of direct item IDs, for better mod compatibility.
- Added more support for a variety of Fabric/NeoForge conventional tags.
- Reformatted some tags to be more consistent.
### Fixes
- Fixed Pokédex sometimes crashing when switching forms.
- Fixed Pokédex interface not transitioning out when closed.
- Fixed texture dimensions for the interact interface.
- Fixed crash related to Tom's Simple Storage mod and Fossil Machine.
- Fixed texture dimensions for the player and Pokémon interact interface.
- Fixed crash related to Tom's Simple Storage mod and the Fossil Machine.
- Fixed not being able to retrieve a fossil from the Fossil Machine with an empty hand.
- Fixed Pokémon being collidable while being captured by a Poké Ball.
- Fixed Pokémon being collidable (collidible? collissionable? kaleidoscopable?) while being captured by a Poké Ball.
- Fixed `full_party`, `own_zangoose_seviper`, `use_revive` and `use_candy` Advancement triggers.
- Fixed `healing_machine` Advancement by using the correct 1.21 trigger.
- Fix Display Cases not dropping items if destroyed through explosions.
- Fixed an issue where the first Pokémon in the pastured Pokémon list clipped into the interface.
- Fixed all Pokémon facing South on spawn.
- Parametric particle motion now works.
- Event spawned particles now work.
- Particles can now have independent coordinate spaces.
- Fixed bait being consumed when not reeling in any Pokémon.
- Fixed bait being consumed even when not reeling in any Pokémon.
- Fixed Miltank milk magically disappearing out of your bucket.
- Fixed Pokémon nicknames migrating from 1.5.2 not being displayed properly.
- Fixed capitalization in one of our config fields, but allowing typo'd version to still be valid.
- Fixed Poké Rods not working if lure or luck of the sea enchantments get removed by other mods.
- Fixed crashes related to Pokémon when they are ready to evolve while holding an enchanted item.
- Fixed crashes that sometimes occur when evolving Nincada.
- Fixed plants not being compostible on NeoForge.
- Fixed capitalization in one of our config options. It was a very important fix. Very important. Old configs are fine.
- Fixed Poké Rods not working if Lure or Luck of the Sea enchantments get removed by other mods.
- Fixed crashes related to Pokémon when they are ready to evolve while holding an enchanted item. Very specific.
- Fixed a crash that sometimes occurred when evolving Nincada.
- Fixed Cobblemon plants not being compostable on NeoForge.
- Fixed hide UI (F1 key) not hiding the party overlay.
- Fixed NPC MoLang command `player_lose_command` not working.
- Corrected misaligned tooltips with editboxes in the NPC editor screen.
- Fixed misaligned tooltips with edit boxes in the NPC editor screen.
- Fixed Pokémon riding two boats when attempting to deploy a platform on water.
- Made berry trees be shearable by dispenser blocks.
- Fixed the summary screen showing there's experience to reach the next level when at level cap.
- Fixed the summary screen showing there's experience to reach the next level when they are at the level cap.
- Fixed Pokémon forgetting moves when evolving on specific cases.
- Fixed Adorn compatibility, including improvements when using JEI/REI (Apricorn items now show up under the collapsed entries rather than standalone).
- Fixed error message appearing on battle log when using Solar Beam with Sunny Day.
@@ -145,48 +165,68 @@
- Fixed `/pokedex grant all` command not giving male/female/shininess completion for some Pokémon.
- Fixed `/pokedex grant only` and `/pokedex remove only` not respecting the form parameter passed.
- Fixed variant forms appearing incorrectly in the Pokédex when the normal form had not been unlocked.
- Fixed Pokémon occasionally being shot into the sky during battle.
- Fixed Pokémon occasionally being shot into the sky during battle. No Pokémon were harmed by this bug, probably.
- Fixed NPC editing GUI not updating aspects until a game restart.
- Fix some users being unable to open their PC if a Pokémon in said PC had a lot of pp raises beyond normal bounds
- Fix some color variants (dubwool, conkeldurr and undyed wooloo) missing in the Pokédex
- Fix invalid species or held_items causing Players to not be able to load into their world anymore (commonly happening after removing addons/mods)
- Fixed some users being unable to open their PC if a Pokémon in it had a lot of PP raises beyond normal bounds. How did you get those, anyway? Tell me or the Bellossom gets it.
- Fixed some color variants (Dubwool, Conkeldurr and Undyed wooloo) being missing in the Pokédex.
- Fixed invalid species or held items causing Players to not be able to load into their world anymore (commonly happening after removing addons/mods).
- Fixed Wooloo variants not being automatically registered in the owner's Pokédex when dyed.
- Fixed Vivichoke Dip and Leek and Potato Stew not returning a bowl upon consumption.
- Fixed Fossil Restoration Machine not accepting Hay Bales.
- Fixed Potion items so that they no longer apply over double their intended healing value.
- Fixed Fast Ball capture rate applying to all Pokémon.
- Fix "learned new move" messages appearing for already known moves on Pokémon evolutions.
- Fix Pokémon Item Models breaking shadows nearby when being placed in Display Cases or Item Frames.
- Fixed Berries not giving bonus yields when planted in their preferred biomes
- Fix NeoForge not supporting "SodiumDynamicLights"
- Fix Players disconnecting from servers if they made changes to certain config options
- Fix JSON stores not loading properly if player with shouldered Pokémon is migrating from 1.5.2 into 1.6
- Fix PokemonProperties ability=myAbility being declared as forced despite being legal for the Pokémon
- Fixed type formatting in Pokédex scanner mode when dual types require two lines
- Fix trading sometimes crashing the game/server
- Fixed Vivichoke Dip and Leek & Potato Stew not returning a bowl upon consumption.
- Fixed Fossil Restoration Tank not accepting Hay Bales as organic material.
- Fixed Potion items applying double their intended healing value.
- Fixed Fast Ball capture bonuses applying to all Pokémon, making it the Best Ball instead of the Mediocre Edge-Case Ball.
- Fixed "learned new move" messages appearing for already-known moves on Pokémon evolutions.
- Fixed Pokémon Item Models breaking shadows nearby when being placed in Display Cases or Item Frames.
- Fixed berries not giving bonus yields when planted in their preferred biomes. I'm sure we've fixed that 5 times now.
- Fixed the NeoForge version not supporting "SodiumDynamicLights".
- Fixed players disconnecting from servers if they made changes to certain config options.
- Fixed players with shouldered Pokémon not being able to rejoin their 1.5.2 worlds using 1.6.
- Fixed `PokemonProperties` utilizing `ability=<some ability>` being treated as a forced ability even when it is a legal ability for the Pokémon.
- Fixed type formatting in Pokédex scanner mode when dual types require two lines.
- Fixed trading sometimes crashing the game or server.
- Fixed Wild shiny sounds not respecting the `shinyNoticeParticlesDistance` config setting.
- Fixed Pokémon being able to evolve mid-battle.
- Fixed NPC held items being able to be stolen by players. Don't be a thief!
- Fixed evolutions that require a held item consuming it as soon as meeting requirements when it should only be consumed upon evolution.
- Fixed Pokémon showing only the default form when selecting them as a target in battle.
- Fixed a possible error coming out of reeling fishing rods in specific situations.
- Fixed incorrect weights being used when Poké Fishing with Luck of the Sea.
- Parametric particle motion now works.
- Event-spawned particles now work.
- Particles can now have independent coordinate spaces.
### Developer
- Updated the Pokédex data updated events to always include a Pokemon instance, and optionally a DisguiseData instance.
- Updated the Pokédex data updated events to always include a `Pokemon` instance, and optionally a `DisguiseData` instance.
- Updated fields in `SpawnNPCPacket` and `SpawnPokemonPacket` to be visible and mutable.
- Updated `UnvalidatedPlaySoundS2CPacket` to be public instead of internal and made its fields mutable.
- Added `hideNameTag` field and `HideNPCNameTag` nbt tag to `NPCEntity` to allow hiding the name tag of the NPC.
- Added the player to `PokerodReelEvent` so you know who is doing the reeling.
### Molang & Datapacks
### MoLang & Datapacks
- Added flows for:
- `forme_change`: Triggered when a Pokémon changes form in battle.
- `mega_evolution`: Triggered when a Pokémon mega evolves in battle. (Note: Third party mods are required for this feature currently)
- `zpower_used`: Triggered when a Pokémon uses a Z-Power move in battle. (Note: Third party mods are required for this feature currently)
- `terastallization`: Triggered when a Pokémon terastallizes in battle. (Note: Third party mods are required for this feature currently)
- `mega_evolution`: Triggered when a Pokémon mega evolves in battle. (Note: Third-party mods are required for this feature currently)
- `zpower_used`: Triggered when a Pokémon uses a Z-Power move in battle. (Note: Third-party mods are required for this feature currently)
- `terastallization`: Triggered when a Pokémon terastallizes in battle. (Note: Third-party mods are required for this feature currently)
- `battle_fainted`: Triggered when a Pokémon faints in battle.
- `battle_fled`: Triggered when a Player flees from battle.
- `battle_fled`: Triggered when a player flees from battle.
- `battle_started_pre`: Triggered when a battle starts. Cancelable!
- `battle_started_post`: Triggered when a battle starts.
- `apricorn_harvested`: Triggered when an apricorn is harvested.
- `apricorn_harvested`: Triggered when an Apricorn is harvested.
- `thrown_pokeball_hit`: Triggered when a thrown Pokéball hits a Pokémon.
- `level_up`: Triggered when a Pokémon levels up.
- `pokemon_fainted`: Triggered when a Pokémon faints.
- `pokemon_gained`: Triggered when a Player gains a Pokémon.
- Added molang functions:
- `pokemon_gained`: Triggered when a player gains a Pokémon.
- Added MoLang functions:
- For Pokémon:
- `pokemon.apply(PokemonProperties)`: Applies the given properties to the Pokémon.
- `pokemon.owner`: Returns the owner of the Pokémon or 0.0 if there is no owner or they are not online.
- For all entities:
- `entity.is_standing_on_blocks(depth, blocks...)`: Returns whether the specified entity is standing on a specific block or set of blocks. Example usage: `q.is_standing_on_blocks(2, minecraft:sand)`
- Added NPC field:
- `hideNameTag`: Hides the name tag of the NPC.
- Added `baseScale` property to NPCs.
- Added MoLang particle queries for getting distance to targeted entities.
## [1.6.0 - The Record Catch Update (December 25th, 2024)](#1-6-0)
#### "Now that there's a fishing mechanic, the mod is actually good!"
@@ -2089,5 +2129,4 @@ Thank you so much to all of our community translators that bring the mod to the
- Added species, ability, and move translations for `ko_ko`, `jp_jp`, `fr_fr`, `es_es`, `it_it`, and `zh_cn`.
## [1.0.0 (November 12th, 2022)](#1-0-0)
- Initial release.
- Initial release.
@@ -0,0 +1,128 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix3f;
import org.joml.Vector3f;
import java.util.function.Function;
public interface Rollable {
//The directions specified by all of the vectors in this class are from the perspective
//of an observer looking at the front of the player model
//These vectors aren't actually accurate, since "forward" can be any of +x -x +z -z depending on the rotation about
//the world-Y axis of the player
Vector3f FORWARDS = new Vector3f(0, 0, 1);
Vector3f LEFT = new Vector3f(1, 0, 0);
Vector3f UP = new Vector3f(0, 1, 0);
@Nullable Matrix3f getOrientation();
Rollable updateOrientation(Function<Matrix3f, Matrix3f> update);
/**
* @return The forward vector (0, 0, 1) after the rotation matrix is applied.
*/
default Vector3f getForwardVector() {
if (getOrientation() == null) return new Vector3f(FORWARDS);
return getOrientation().transform(FORWARDS, new Vector3f());
}
/**
* @return The left vector (1, 0, 0) after the rotation matrix is applied.
*/
default Vector3f getLeftVector() {
if (getOrientation() == null) return new Vector3f(LEFT);
return getOrientation().transform(LEFT, new Vector3f());
}
/**
* @return The up vector (0, 1, 0) after the rotation matrix is applied.
*/
default Vector3f getUpVector() {
if (getOrientation() == null) return new Vector3f(UP);
return getOrientation().transform(UP, new Vector3f());
}
/**
*
* @param yaw change in degrees
* @return The Rollable object this method was called on
*/
default Rollable rotateYaw(float yaw) {
return updateOrientation(prev -> prev.rotateY((float) Math.toRadians(-yaw)));
}
/**
*
* @param pitch change in degrees
* @return The Rollable object this method was called on
*/
default Rollable rotatePitch(float pitch) {
return updateOrientation(prev -> prev.rotateX((float) Math.toRadians(-pitch)));
}
/**
*
* @param roll change in degrees
* @return The Rollable object this method was called on
*/
default Rollable rotateRoll(float roll) {
return updateOrientation(prev -> prev.rotateZ((float) Math.toRadians(-roll)));
}
/**
* Order matters when rotating an object. If you need a different order, individually call rotateYaw, rotatePitch, and rotateRoll
*
* @param yaw change in degrees
* @param pitch change in degrees
* @param roll change in degrees
* @return The Rollable object this method was called on
*/
default Rollable rotate(float yaw, float pitch, float roll) {
return rotateYaw(yaw).rotatePitch(pitch).rotateRoll(roll);
}
/**
* @return The yaw angle in degrees as a float.
* Value is between [-90, 90] with 0 being straight forward, 90 being straight down, and -90 being straight up
*/
default float getYaw() {
return (float) (180F - Math.toDegrees(FORWARDS.angleSigned(getForwardVector(), UP)));
}
/**
* Get the pitch angle in degrees as a float.
* Value is between [-180, 180] with 0 being South, 90 being West, 180/-180 being North, and -90 being East
*/
default float getPitch() {
return (float) Math.toDegrees(Math.asin(getForwardVector().y));
}
/**
* Get the roll angle in degrees as a float.
* Value is between [-180, 180] with 0 being no roll (normal), 90 being 90 degrees CW, 180/-180 being 180 degrees CW/CCW, and -90 being 90 degrees CCW
*/
default float getRoll() {
var upVector = getUpVector();
var forwardVector = getForwardVector();
return (float) Math.toDegrees(upVector.angleSigned(UP, forwardVector));
}
boolean shouldRoll();
void clearRotation();
}
@@ -0,0 +1,96 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.Rollable;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.world.entity.Entity;
import org.joml.Matrix3f;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Camera.class)
public abstract class CameraMixin {
@Shadow private Entity entity;
@Shadow @Final private Quaternionf rotation;
@Shadow @Final private Vector3f forwards;
@Shadow @Final private Vector3f up;
@Shadow @Final private Vector3f left;
@Shadow private float xRot;
@Shadow private float yRot;
@Shadow public abstract float getXRot();
@Shadow public abstract float getYRot();
@Unique private float returnTimer = 0;
@Unique private float rollAngleStart = 0;
@Unique Minecraft minecraft = Minecraft.getInstance();
@Unique boolean disableRollableCameraDebug = false;
@Inject(method = "setRotation", at = @At("HEAD"), cancellable = true)
public void open_camera$setRotation(float f, float g, CallbackInfo ci) {
if (!(this.entity instanceof Rollable rollable) || disableRollableCameraDebug) return;
if (!rollable.shouldRoll() && rollable.getOrientation() != null) {
if(this.returnTimer < 1) {
//Rotation is taken from entity since we no longer handle mouse ourselves
//Stops a period of time when you can't input anything.
rollable.getOrientation().set(
new Matrix3f()
.rotateY((float) Math.toRadians(180 - this.entity.getYRot()))
.rotateX((float) Math.toRadians(-this.entity.getXRot()))
);
if(rollAngleStart == 0){
this.returnTimer = 1;
rollable.clearRotation();
return;
}
rollable.getOrientation().rotateZ((float) Math.toRadians(-rollAngleStart*(1-returnTimer)));
applyRotation();
this.returnTimer += .05F;
ci.cancel();
} else {
this.returnTimer = 1;
rollable.clearRotation();
}
return;
}
if (rollable.getOrientation() == null) return;
applyRotation();
this.returnTimer = 0;
this.rollAngleStart = rollable.getRoll();
ci.cancel();
}
@Unique
private void applyRotation(){
if (!(this.entity instanceof Rollable rollable) || rollable.getOrientation() == null) return;
var newRotation = rollable.getOrientation().normal(new Matrix3f()).getNormalizedRotation(new Quaternionf());
if (this.minecraft.options.getCameraType().isMirrored()) {
newRotation.rotateY((float)Math.toRadians(180));
}
this.rotation.set(newRotation);
this.xRot = rollable.getPitch();
this.yRot = rollable.getYaw();
this.forwards.set(rollable.getForwardVector());
this.up.set(rollable.getUpVector());
this.left.set(rollable.getLeftVector());
}
}
@@ -0,0 +1,66 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.client.render.player.MountedPlayerRenderer;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.HashMap;
@Mixin(HumanoidModel.class)
public class HumanoidModelMixin {
@Unique HashMap<String, ModelPart> relevantPartsByName = new HashMap<>();
@Shadow @Final
public ModelPart head;
@Shadow @Final
public ModelPart rightArm;
@Shadow @Final
public ModelPart leftArm;
@Shadow @Final
public ModelPart rightLeg;
@Shadow @Final
public ModelPart leftLeg;
@Inject(method = "setupAnim*", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/model/geom/ModelPart;copyFrom(Lnet/minecraft/client/model/geom/ModelPart;)V", shift = At.Shift.BEFORE))
public void cobblemon$animateRiders(
LivingEntity entity,
float limbSwing,
float limbSwingAmount,
float ageInTicks,
float netHeadYaw,
float headPitch,
CallbackInfo ci
) {
if (relevantPartsByName.isEmpty()) {
relevantPartsByName.put("arm_left", leftArm);
relevantPartsByName.put("arm_right", rightArm);
relevantPartsByName.put("leg_left", leftLeg);
relevantPartsByName.put("leg_right", rightLeg);
relevantPartsByName.put("head", head);
}
Entity vehicle = entity.getVehicle();
if (vehicle instanceof PokemonEntity && entity instanceof AbstractClientPlayer) {
MountedPlayerRenderer.INSTANCE.animate((PokemonEntity) vehicle, (AbstractClientPlayer) entity, relevantPartsByName, netHeadYaw, headPitch, ageInTicks, limbSwing, limbSwingAmount);
}
}
}
@@ -8,16 +8,21 @@
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.Rollable;
import com.cobblemon.mod.common.item.PokedexItem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.ItemInHandRenderer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.item.ItemStack;
import org.joml.Quaternionf;
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.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ItemInHandRenderer.class)
@@ -27,5 +32,15 @@ public class ItemInHandRendererMixin {
if (abstractClientPlayer.isUsingItem() && abstractClientPlayer.getUseItem().getItem() instanceof PokedexItem) {
ci.cancel();
}
else if (abstractClientPlayer instanceof Rollable rollable && rollable.shouldRoll()) {
}
}
@Redirect(method = "renderHandsWithItems", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;mulPose(Lorg/joml/Quaternionf;)V", ordinal = 1))
private void cobblemon$renderHandswithItems(PoseStack instance, Quaternionf quaternion) {
if (!(Minecraft.getInstance().player instanceof Rollable rollable && rollable.shouldRoll())) {
instance.mulPose(quaternion);
}
}
}
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.Rollable;
import com.cobblemon.mod.common.client.CobblemonClient;
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding;
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext;
@@ -22,17 +23,19 @@ import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(MouseHandler.class)
public class MouseHandlerMixin {
@Shadow
private double accumulatedScrollY;
@Shadow private double accumulatedScrollY;
@Shadow @Final private Minecraft minecraft;
@Unique SmoothDouble pitchSmoother = new SmoothDouble();
@Unique SmoothDouble rollSmoother = new SmoothDouble();
@Shadow @Final private SmoothDouble smoothTurnY;
@Shadow @Final private SmoothDouble smoothTurnX;
@@ -93,7 +96,6 @@ public class MouseHandlerMixin {
)
)
public boolean cobblemon$modifyRotation(LocalPlayer player, double cursorDeltaX, double cursorDeltaY, @Local(argsOnly = true) double d) {
// I know this technically doesn't need to be a WrapWithCondition, but it'll make things easier later for riding.
PokedexUsageContext usageContext = CobblemonClient.INSTANCE.getPokedexUsageContext();
if (usageContext.getScanningGuiOpen()) {
this.smoothTurnY.reset();
@@ -105,7 +107,30 @@ public class MouseHandlerMixin {
player.turn(this.accumulatedDX * sensitivity, (this.accumulatedDY * sensitivity));
return false;
}
return true;
if (!(player instanceof Rollable rollable)) return true;
if (!rollable.shouldRoll()) {
pitchSmoother.reset();
rollSmoother.reset();
return true;
}
var pitch = pitchSmoother.getNewDeltaValue(cursorDeltaY * 0.15f, d);
var roll = rollSmoother.getNewDeltaValue(cursorDeltaX * 0.15f, d);
rollable.rotate(0.0F, (float)pitch, (float)roll);
return false;
}
@Inject(method = "handleAccumulatedMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MouseHandler;isMouseGrabbed()Z", ordinal = 0))
private void cobblemon$maintainMovementWhenInScreens(CallbackInfo ci, @Local(ordinal = 1) double e) {
if (minecraft.player == null) return;
if (!(minecraft.player instanceof Rollable rollable)) return;
if (!rollable.shouldRoll()) return;
if (minecraft.isPaused()) return;
var pitch = pitchSmoother.getNewDeltaValue(0, e);
var roll = rollSmoother.getNewDeltaValue(0, e);
rollable.rotate(0.0F, (float)pitch, (float)roll);
}
}
@@ -10,12 +10,15 @@ package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.Cobblemon;
import com.cobblemon.mod.common.CobblemonItems;
import com.cobblemon.mod.common.Rollable;
import com.cobblemon.mod.common.api.events.CobblemonEvents;
import com.cobblemon.mod.common.api.events.item.LeftoversCreatedEvent;
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies;
import com.cobblemon.mod.common.api.riding.Rideable;
import com.cobblemon.mod.common.api.storage.party.PartyStore;
import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore;
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.pokedex.scanner.PokedexEntityData;
import com.cobblemon.mod.common.pokedex.scanner.ScannableEntity;
import com.cobblemon.mod.common.pokemon.FormData;
@@ -26,6 +29,10 @@ import com.cobblemon.mod.common.util.CompoundTagExtensionsKt;
import com.cobblemon.mod.common.util.CompoundTagUtilities;
import com.cobblemon.mod.common.util.DataKeys;
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component;
@@ -38,8 +45,10 @@ import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix3f;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -53,10 +62,11 @@ import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
@Mixin(Player.class)
public abstract class PlayerMixin extends LivingEntity implements ScannableEntity {
public abstract class PlayerMixin extends LivingEntity implements Rollable, ScannableEntity {
@Shadow public abstract CompoundTag getShoulderEntityLeft();
@@ -74,6 +84,7 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
@Shadow public abstract void displayClientMessage(Component message, boolean overlay);
@Unique private Matrix3f orientation = null;
protected PlayerMixin(EntityType<? extends LivingEntity> p_20966_, Level p_20967_) {
super(p_20966_, p_20967_);
@@ -225,4 +236,83 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
public LivingEntity resolveEntityScan() {
return this;
}
}
@Override
public void absMoveTo(double x, double y, double z, float yaw, float pitch) {
if (shouldRoll()) {
this.absMoveTo(x, y, z);
this.setYRot(yaw % 360.0f);
this.setXRot(pitch % 360.0f);
this.yRotO = this.getYRot();
this.xRotO = this.getXRot();
}
else {
this.absMoveTo(x, y, z);
this.absRotateTo(yaw, pitch);
}
}
@Inject(method = "tick", at = @At("HEAD"))
public void tick(CallbackInfo ci) {
if (this.shouldRoll()) {
// Proof of concept for yaw movement
if (this.getMainHandItem().is(Items.STICK)) {
this.rotateYaw(2);
}
else if (this.getMainHandItem().is(Items.BLAZE_ROD)) {
this.rotateYaw(-2);
}
}
}
@Override
public Matrix3f getOrientation() {
return orientation;
}
@Override
public Rollable updateOrientation(Function<Matrix3f, Matrix3f> update) {
if (!shouldRoll()) return this;
if (this.orientation == null) {
this.orientation = new Matrix3f();
this.rotate(getYRot() - 180, getXRot(), 0);
}
this.orientation = update.apply(this.orientation);
setYRot(this.getYaw());
setXRot(this.getPitch());
this.yRotO = this.getYRot();
this.xRotO = this.getXRot();
return this;
}
@Override
public boolean shouldRoll() {
LocalPlayer player = Minecraft.getInstance().player;
if (!this.equals(player)) return false;
if (player.isHolding(Items.DIAMOND)) return true;
var playerVehicle = player.getVehicle();
if (playerVehicle == null) return false;
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return false;
return pokemonEntity.getRiding().shouldRoll(pokemonEntity);
}
@Override
public void clearRotation() {
this.orientation = null;
}
@WrapOperation(
method = "rideTick()V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;wantsToStopRiding()Z")
)
public boolean delegateDismountToController(Player instance, Operation<Boolean> original) {
if (this.getVehicle() instanceof Rideable vehicle) {
return vehicle.getRiding().dismountOnShift() && original.call(instance);
}
return original.call(instance);
}
}
@@ -8,11 +8,29 @@
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.Rollable;
import com.cobblemon.mod.common.api.riding.Rideable;
import com.cobblemon.mod.common.api.riding.Seat;
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate;
import com.cobblemon.mod.common.client.render.ClientPlayerIcon;
import com.cobblemon.mod.common.client.render.player.PlayerRendererHook;
import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.cobblemon.mod.common.client.render.MatrixWrapper;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.mojang.authlib.minecraft.client.MinecraftClient;
import com.mojang.blaze3d.vertex.PoseStack;
import net.fabricmc.loader.impl.lib.sat4j.core.Vec;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
import net.minecraft.util.Mth;
import net.minecraft.world.phys.Vec3;
import org.joml.Matrix4f;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@@ -20,9 +38,14 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(PlayerRenderer.class)
public class PlayerRendererMixin {
private static boolean disableRollableRenderDebug = false;
@WrapMethod(method = "render")
public void applyRotation(AbstractClientPlayer player, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource multiBufferSource, int i, Operation<Integer> original) {
PlayerRendererHook.INSTANCE.before(player, entityYaw, partialTicks, poseStack, multiBufferSource, i);
original.call(player, entityYaw, partialTicks, poseStack, multiBufferSource, i);
@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);
}
}
@@ -0,0 +1,43 @@
/*
* 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.CobblemonNetwork;
import com.cobblemon.mod.common.Rollable;
import com.cobblemon.mod.common.net.messages.server.orientation.C2SUpdateOrientationPacket;
import net.minecraft.client.player.LocalPlayer;
import org.joml.Matrix3f;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(LocalPlayer.class)
public class LocalPlayerMixin {
@Unique Matrix3f cobblemon$lastOrientation;
@Inject(method = "sendPosition", at = @At("TAIL"))
private void cobblemon_updateRotationMatrix(CallbackInfo ci) {
if (!(this instanceof Rollable rollable)) return;
if (rollable.getOrientation() == cobblemon$lastOrientation) return;
cobblemon$lastOrientation = rollable.getOrientation() != null ? new Matrix3f(rollable.getOrientation()) : null;
CobblemonNetwork.INSTANCE.sendToServer(new C2SUpdateOrientationPacket(rollable.getOrientation()));
}
@Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientPacketListener;send(Lnet/minecraft/network/protocol/Packet;)V"))
private void cobblemon_updateRotationMatrixPassenger(CallbackInfo ci) {
if (!(this instanceof Rollable rollable)) return;
if (rollable.getOrientation() == cobblemon$lastOrientation) return;
cobblemon$lastOrientation = rollable.getOrientation() != null ? new Matrix3f(rollable.getOrientation()) : null;
CobblemonNetwork.INSTANCE.sendToServer(new C2SUpdateOrientationPacket(rollable.getOrientation()));
}
}
@@ -0,0 +1,32 @@
/*
* 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.entity;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import net.minecraft.world.entity.Entity;
import org.jetbrains.annotations.Nullable;
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(Entity.class)
public abstract class EntityMixin {
@Shadow @Nullable public abstract Entity getVehicle();
@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) {
ci.cancel();
}
}
}
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.renderer;
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
import org.spongepowered.asm.mixin.Mixin;
/**
* @author landonjw
*/
@Mixin(LivingEntityRenderer.class)
public abstract class LivingEntityRendererMixin {
// @Redirect(
// method = "render(Lnet/minecraft/entity/LivingEntity;FFLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V",
// at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;hasVehicle()Z"),
// slice = @Slice(
// from = @At(value = "INVOKE", target = "Lnet/minecraft/util/math/MathHelper;lerpAngleDegrees(FFF)F"),
// to = @At(value = "TAIL")
// )
// )
// private boolean dodgeRenderer(LivingEntity instance) {
// return false;
// }
}
@@ -0,0 +1,39 @@
/*
* 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.renderer;
import com.cobblemon.mod.common.client.render.player.MountedPlayerRenderer;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
/**
* @author landonjw
*/
@Mixin(PlayerRenderer.class)
public class PlayerEntityRendererMixin {
@Inject(
method = "setupRotations(Lnet/minecraft/client/player/AbstractClientPlayer;Lcom/mojang/blaze3d/vertex/PoseStack;FFFF)V",
at = @At("HEAD")
)
private void doABibarelRoll$modifyRoll(AbstractClientPlayer player, PoseStack poseStack, float a, float b, float partialTicks, float i, CallbackInfo ci) {
if (player.isPassenger()) {
var vehicle = player.getVehicle();
if (vehicle instanceof PokemonEntity entity) {
MountedPlayerRenderer.INSTANCE.render(player, entity, poseStack);
}
}
}
}
@@ -0,0 +1,62 @@
/*
* 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.riding;
import net.minecraft.client.player.LocalPlayer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(LocalPlayer.class)
public class JetMixin {
@Shadow private int jumpRidingTicks;
@Shadow private float jumpRidingScale;
private float jetStrength;
// @Redirect(method = "tickMovement", at = @At(target = "Lnet/minecraft/entity/JumpingMount;getJumpCooldown()I", value = "INVOKE"))
// public int cobblemon$tryHandlingJet(JumpingMount mount) {
// if(mount instanceof PokemonEntity pokemon) {
//// if(pokemon.getDataTracker().get(PokemonEntity.MOVING)) {
//// ++this.field_3938;
//// if (this.field_3938 < 11) {
//// this.jetStrength = (float) this.field_3938 * 0.1F;
//// } else {
// this.mountJumpStrength = 0.8F + 2.0F / (float) (this.field_3938 - 9) * 0.1F;
//// }
//// } else {
//// this.field_3938 = 0;
//// this.jetStrength = 0;
//// }
//
//// return -1;
// }
//
// return 0;
// }
@Inject(
method = "aiStep",
at = @At(
target = "Lnet/minecraft/client/player/LocalPlayer;jumpRidingScale:F",
value = "FIELD",
ordinal = 4,
shift = At.Shift.AFTER
),
locals = LocalCapture.CAPTURE_FAILSOFT
)
public void cobblemon$applyCachedJumpStrength(CallbackInfo ci) {
this.jumpRidingScale = this.jetStrength;
}
}
@@ -12,6 +12,14 @@ object CobblemonBuildDetails {
const val BRANCH = "{{ branch | default("Not Specified") }}"
fun smallCommitHash(): String {
if(this.GIT_COMMIT.equals("Not Specified")) {
return "Unknown"
}
return this.GIT_COMMIT.substring(0, 7)
}
fun version(): String {
return this.VERSION + if(this.SNAPSHOT) "+${this.smallCommitHash()}" else ""
}
}
@@ -51,7 +51,14 @@ import com.cobblemon.mod.common.client.net.storage.pc.OpenPCHandler
import com.cobblemon.mod.common.client.net.storage.pc.SetPCBoxPokemonHandler
import com.cobblemon.mod.common.client.net.storage.pc.SetPCPokemonHandler
import com.cobblemon.mod.common.client.net.toast.ToastPacketHandler
import com.cobblemon.mod.common.client.net.trade.*
import com.cobblemon.mod.common.client.net.trade.TradeAcceptanceChangedHandler
import com.cobblemon.mod.common.client.net.trade.TradeCancelledHandler
import com.cobblemon.mod.common.client.net.trade.TradeCompletedHandler
import com.cobblemon.mod.common.client.net.trade.TradeOfferExpiredHandler
import com.cobblemon.mod.common.client.net.trade.TradeOfferNotificationHandler
import com.cobblemon.mod.common.client.net.trade.TradeProcessStartedHandler
import com.cobblemon.mod.common.client.net.trade.TradeStartedHandler
import com.cobblemon.mod.common.client.net.trade.TradeUpdatedHandler
import com.cobblemon.mod.common.net.PacketRegisterInfo
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
import com.cobblemon.mod.common.net.messages.client.SetClientPlayerDataPacket
@@ -93,14 +100,37 @@ import com.cobblemon.mod.common.net.messages.client.storage.party.InitializePart
import com.cobblemon.mod.common.net.messages.client.storage.party.MoveClientPartyPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.party.SetPartyPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.party.SetPartyReferencePacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.*
import com.cobblemon.mod.common.net.messages.client.storage.pc.ClosePCPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.InitializePCPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.MoveClientPCPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.OpenPCPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCBoxPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCPokemonPacket
import com.cobblemon.mod.common.net.messages.client.toast.ToastPacket
import com.cobblemon.mod.common.net.messages.client.trade.*
import com.cobblemon.mod.common.net.messages.client.trade.TradeAcceptanceChangedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeCancelledPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeCompletedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferExpiredPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferNotificationPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeProcessStartedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeUpdatedPacket
import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
import com.cobblemon.mod.common.net.messages.client.ui.PokedexUIPacket
import com.cobblemon.mod.common.net.messages.client.ui.SummaryUIPacket
import com.cobblemon.mod.common.net.messages.server.*
import com.cobblemon.mod.common.net.messages.server.battle.*
import com.cobblemon.mod.common.net.messages.server.BattleChallengePacket
import com.cobblemon.mod.common.net.messages.server.BattleChallengeResponsePacket
import com.cobblemon.mod.common.net.messages.server.BenchMovePacket
import com.cobblemon.mod.common.net.messages.server.RequestMoveSwapPacket
import com.cobblemon.mod.common.net.messages.server.RequestPlayerInteractionsPacket
import com.cobblemon.mod.common.net.messages.server.SelectStarterPacket
import com.cobblemon.mod.common.net.messages.server.SendOutPokemonPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleSelectActionsPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamLeavePacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamRequestPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamResponsePacket
import com.cobblemon.mod.common.net.messages.server.battle.RemoveSpectatorPacket
import com.cobblemon.mod.common.net.messages.server.battle.SpectateBattlePacket
import com.cobblemon.mod.common.net.messages.server.block.AdjustBlockEntityViewerCountPacket
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectCancelledPacket
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectedPacket
@@ -111,6 +141,7 @@ import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyPoke
import com.cobblemon.mod.common.net.messages.server.dialogue.EscapeDialoguePacket
import com.cobblemon.mod.common.net.messages.server.dialogue.InputToDialoguePacket
import com.cobblemon.mod.common.net.messages.server.npc.SaveNPCPacket
import com.cobblemon.mod.common.net.messages.server.orientation.C2SUpdateOrientationPacket
import com.cobblemon.mod.common.net.messages.server.pasture.PasturePokemonPacket
import com.cobblemon.mod.common.net.messages.server.pasture.UnpastureAllPokemonPacket
import com.cobblemon.mod.common.net.messages.server.pasture.UnpasturePokemonPacket
@@ -130,9 +161,21 @@ import com.cobblemon.mod.common.net.messages.server.storage.pc.MovePartyPokemonT
import com.cobblemon.mod.common.net.messages.server.storage.pc.ReleasePCPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.SwapPCPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.UnlinkPlayerFromPCPacket
import com.cobblemon.mod.common.net.messages.server.trade.*
import com.cobblemon.mod.common.net.serverhandling.*
import com.cobblemon.mod.common.net.serverhandling.battle.*
import com.cobblemon.mod.common.net.messages.server.trade.AcceptTradeRequestPacket
import com.cobblemon.mod.common.net.messages.server.trade.CancelTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.ChangeTradeAcceptancePacket
import com.cobblemon.mod.common.net.messages.server.trade.OfferTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.PerformTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.UpdateTradeOfferPacket
import com.cobblemon.mod.common.net.serverhandling.ChallengeHandler
import com.cobblemon.mod.common.net.serverhandling.ChallengeResponseHandler
import com.cobblemon.mod.common.net.serverhandling.RequestInteractionsHandler
import com.cobblemon.mod.common.net.serverhandling.battle.BattleSelectActionsHandler
import com.cobblemon.mod.common.net.serverhandling.battle.RemoveSpectatorHandler
import com.cobblemon.mod.common.net.serverhandling.battle.SpectateBattleHandler
import com.cobblemon.mod.common.net.serverhandling.battle.TeamLeaveHandler
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestHandler
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestResponseHandler
import com.cobblemon.mod.common.net.serverhandling.block.AdjustBlockEntityViewerCountHandler
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectCancelledHandler
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectedHandler
@@ -144,6 +187,7 @@ import com.cobblemon.mod.common.net.serverhandling.dialogue.EscapeDialogueHandle
import com.cobblemon.mod.common.net.serverhandling.dialogue.InputToDialogueHandler
import com.cobblemon.mod.common.net.serverhandling.evolution.AcceptEvolutionHandler
import com.cobblemon.mod.common.net.serverhandling.npc.SaveNPCHandler
import com.cobblemon.mod.common.net.serverhandling.orientation.OrientationPacketHandler
import com.cobblemon.mod.common.net.serverhandling.pasture.PasturePokemonHandler
import com.cobblemon.mod.common.net.serverhandling.pasture.UnpastureAllPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.pasture.UnpasturePokemonHandler
@@ -166,7 +210,12 @@ import com.cobblemon.mod.common.net.serverhandling.storage.pc.MovePartyPokemonTo
import com.cobblemon.mod.common.net.serverhandling.storage.pc.ReleasePartyPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.pc.SwapPCPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.pc.UnlinkPlayerFromPCHandler
import com.cobblemon.mod.common.net.serverhandling.trade.*
import com.cobblemon.mod.common.net.serverhandling.trade.AcceptTradeRequestHandler
import com.cobblemon.mod.common.net.serverhandling.trade.CancelTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.ChangeTradeAcceptanceHandler
import com.cobblemon.mod.common.net.serverhandling.trade.OfferTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.PerformTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.UpdateTradeOfferHandler
import com.cobblemon.mod.common.util.server
import net.minecraft.server.level.ServerPlayer
@@ -443,6 +492,9 @@ object CobblemonNetwork {
// NPC packets
list.add(PacketRegisterInfo(SaveNPCPacket.ID, SaveNPCPacket::decode, SaveNPCHandler))
// Orientation packet(s)
list.add(PacketRegisterInfo(C2SUpdateOrientationPacket.ID, C2SUpdateOrientationPacket::decode, OrientationPacketHandler))
return list
}
@@ -450,4 +502,4 @@ object CobblemonNetwork {
//logger.info("[S->C] ${packet.type()}")
Cobblemon.implementation.networkManager.sendPacketToPlayer(player, packet)
}
}
}
@@ -55,6 +55,7 @@ class ActiveDialogue(var playerEntity: ServerPlayer, var dialogueReference: Dial
)
dialogueReference.initializationAction.invoke(this)
setPage(currentPage)
if (!completion.isDone) {
val packet = DialogueOpenedPacket(this, true)
@@ -52,6 +52,6 @@ object DialogueManager {
fun stopDialogue(playerEntity: ServerPlayer) {
val activeDialogue = playerEntity.activeDialogue ?: return
DialogueClosedPacket(activeDialogue.dialogueId).sendToPlayer(playerEntity)
activeDialogues.remove(activeDialogue.dialogueId)
activeDialogues.remove(playerEntity.uuid)
}
}
@@ -49,6 +49,7 @@ import com.cobblemon.mod.common.api.reactive.EventObservable
import com.cobblemon.mod.common.api.reactive.Observable.Companion.filter
import com.cobblemon.mod.common.api.reactive.Observable.Companion.map
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.api.riding.events.SelectDriverEvent
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.server.level.ServerPlayer
@@ -232,4 +233,12 @@ object CobblemonEvents {
val HATCH_EGG_PRE = CancelableObservable<HatchEggEvent.Pre>()
@JvmField
val HATCH_EGG_POST = EventObservable<HatchEggEvent.Post>()
// -------------------------------------------------------------------------------------
//
// Riding
//
// -------------------------------------------------------------------------------------
@JvmField
val SELECT_DRIVER = EventObservable<SelectDriverEvent>()
}
@@ -57,6 +57,7 @@ class NPCClass {
var isInvulnerable = false
var isLeashable = true
var allowProjectileHits = true
var hideNameTag = false
// If you're adding stuff here, add it to NPCPreset and NPCClassAdapter too
@@ -97,6 +98,7 @@ class NPCClass {
buffer.writeBoolean(isInvulnerable)
buffer.writeBoolean(isLeashable)
buffer.writeBoolean(allowProjectileHits)
buffer.writeBoolean(hideNameTag)
}
fun decode(buffer: RegistryFriendlyByteBuf) {
@@ -148,5 +150,6 @@ class NPCClass {
isInvulnerable = buffer.readBoolean()
isLeashable = buffer.readBoolean()
allowProjectileHits = buffer.readBoolean()
hideNameTag = buffer.readBoolean()
}
}
@@ -37,6 +37,7 @@ class NPCPreset {
var isInvulnerable: Boolean? = null
var isLeashable: Boolean? = null
var allowProjectileHits: Boolean? = null
var hideNameTag: Boolean? = null
fun applyTo(npcClass: NPCClass) {
resourceIdentifier?.let { npcClass.resourceIdentifier = it }
@@ -63,5 +64,6 @@ class NPCPreset {
isInvulnerable?.let { npcClass.isInvulnerable = it }
isLeashable?.let { npcClass.isLeashable = it }
allowProjectileHits?.let { npcClass.allowProjectileHits = it }
hideNameTag?.let { npcClass.hideNameTag = it }
}
}
@@ -78,6 +78,7 @@ any number of presets and the properties of those presets will be merged into th
"skill": 5,
"autoHealParty": true,
"randomizePartyOrder": true,
"hideNameTag": false,
"party": {
"type": "simple",
"pokemon": [
@@ -411,4 +412,7 @@ Pokémon in the party.
### ai
The AI property is an array of brain configurations. This is used to configure the behaviours of the NPC. See
the documentation for brain configurations at [AI Configuration](../ai/config/README.md).
the documentation for brain configurations at [AI Configuration](../ai/config/README.md).
### hideNameTag
Whether the NPC's nametag should be hidden or not. Defaults to false.
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.api.pokemon
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.abilities.AbilityPool
import com.cobblemon.mod.common.api.abilities.AbilityTemplate
@@ -32,6 +33,7 @@ import com.cobblemon.mod.common.api.pokemon.moves.Learnset
import com.cobblemon.mod.common.api.pokemon.stats.Stat
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.api.riding.controller.RideController
import com.cobblemon.mod.common.api.spawning.TimeRange
import com.cobblemon.mod.common.api.types.ElementalType
import com.cobblemon.mod.common.api.types.adapters.ElementalTypeAdapter
@@ -46,6 +48,7 @@ import com.cobblemon.mod.common.pokemon.evolution.adapters.NbtItemPredicateAdapt
import com.cobblemon.mod.common.pokemon.evolution.predicate.NbtItemPredicate
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
import com.cobblemon.mod.common.util.adapters.*
import com.cobblemon.mod.common.util.adapters.riding.RideControllerAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.common.collect.HashBasedTable
import com.google.gson.Gson
@@ -100,6 +103,8 @@ object PokemonSpecies : JsonDataRegistry<Species> {
.registerTypeAdapter(EggGroup::class.java, EggGroupAdapter)
.registerTypeAdapter(MobEffect::class.java, RegistryElementAdapter<MobEffect>(BuiltInRegistries::MOB_EFFECT))
.registerTypeAdapter(NbtItemPredicate::class.java, NbtItemPredicateAdapter)
.registerTypeAdapter(RideController::class.java, RideControllerAdapter)
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
.disableHtmlEscaping()
.enableComplexMapKeySerialization()
.create()
@@ -105,9 +105,6 @@ interface Evolution : EvolutionLike {
* @param pokemon The [Pokemon] being evolved.
*/
fun evolve(pokemon: Pokemon): Boolean {
if (this.consumeHeldItem) {
pokemon.swapHeldItem(ItemStack.EMPTY)
}
if (this.optional) {
// All the networking is handled under the hood, see EvolutionController.
return pokemon.evolutionProxy.server().add(this)
@@ -223,6 +220,10 @@ interface Evolution : EvolutionLike {
this.shed(pokemon)
if (this.consumeHeldItem) {
pokemon.swapHeldItem(ItemStack.EMPTY)
}
val ownerPlayer = pokemon.getOwnerPlayer()
if (ownerPlayer != null && ownerPlayer.level().gameRules.getBoolean(CobblemonGameRules.DO_POKEMON_LOOT)) {
drops.drop(
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding
import net.minecraft.world.entity.PlayerRideableJumping
/**
* Represents an entity that supports riding.
*
* @since 1.5.0
*/
interface Rideable : PlayerRideableJumping {
/**
* Denotes the manager responsible for handling any instance of riding taking place on an entity
*/
val riding: RidingManager
}
@@ -0,0 +1,118 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.riding.controller.RideController
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
data class RidingManager(val entity: PokemonEntity) {
var lastSpeed = 0F
var states: MutableMap<ResourceLocation, RidingState> = mutableMapOf()
var deltaRotation = Vec2.ZERO
val runtime: MoLangRuntime by lazy {
MoLangRuntime()
.setup()
.withQueryValue("entity", entity.struct)
.also {
it.environment.query.addFunction("passenger_count") { DoubleValue(entity.passengers.size.toDouble()) }
}
}
fun <T : RidingState> getState(id: ResourceLocation, constructor: (PokemonEntity) -> T): T {
val storedState = states[id]
if (storedState == null) {
val newState = constructor(entity)
states[id] = newState
return newState
}
return storedState as T
}
fun getController(entity: PokemonEntity): RideController? {
return entity.pokemon.riding.controller?.takeIf { it.condition.invoke(entity) }
}
/**
* Responsible for handling riding conditions and transitions amongst controllers. This will tick
* whenever the entity receives a tickControlled interaction.
*/
fun tick(entity: PokemonEntity, driver: Player, input: Vec3) {
val controller = getController(entity) ?: return
val pose = controller.pose(entity)
entity.entityData.set(PokemonEntity.POSE_TYPE, pose)
// driver.displayClientMessage(Component.literal("Speed: ").withStyle { it.withColor(ChatFormatting.GREEN) }.append(Component.literal("$lastSpeed b/t")), true)
}
fun speed(entity: PokemonEntity, driver: Player): Float {
val controller = getController(entity) ?: return 0.05F
this.lastSpeed = controller.speed(entity, driver)
return this.lastSpeed
}
fun controlledRotation(entity: PokemonEntity, driver: Player): Vec2 {
val controller = getController(entity) ?: return entity.rotationVector
val previousRotation = entity.rotationVector
val rotation = controller.rotation(entity, driver)
this.deltaRotation = Vec2(rotation.x - previousRotation.x, rotation.y - previousRotation.y)
return rotation
}
fun clampPassengerRotation(entity: PokemonEntity, driver: LivingEntity) {
val controller = getController(entity) ?: return
return controller.clampPassengerRotation(entity, driver)
}
fun updatePassengerRotation(entity: PokemonEntity, driver: LivingEntity) {
val controller = getController(entity) ?: return
return controller.updatePassengerRotation(entity, driver)
}
fun velocity(entity: PokemonEntity, driver: Player, input: Vec3): Vec3 {
val controller = getController(entity) ?: return Vec3.ZERO
return controller.velocity(entity, driver, input)
}
fun canJump(entity: PokemonEntity, driver: Player): Boolean {
val controller = getController(entity) ?: return false
return controller.canJump(entity, driver)
}
fun jumpVelocity(entity: PokemonEntity, driver: Player, jumpStrength: Int): Vec3 {
val controller = getController(entity) ?: return Vec3.ZERO
return controller.jumpForce(entity, driver, jumpStrength)
}
fun gravity(entity: PokemonEntity, regularGravity: Double): Double? {
val controller = getController(entity) ?: return null
return controller.gravity(entity, regularGravity)
}
fun shouldRoll(entity: PokemonEntity): Boolean {
val controller = getController(entity) ?: return false
return controller.shouldRoll(entity)
}
//FIXME: Make this not just be false for all controllers lol
fun dismountOnShift(): Boolean {
return false
}
}
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.api.riding.controller.RideController
import com.cobblemon.mod.common.util.adapters.riding.RideControllerAdapter
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.getString
import com.cobblemon.mod.common.util.readIdentifier
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.writeString
import net.minecraft.network.RegistryFriendlyByteBuf
class RidingProperties(
val seats: List<Seat> = listOf(),
val conditions: List<Expression> = listOf(),
val controller: RideController? = null
) {
companion object {
fun decode(buffer: RegistryFriendlyByteBuf): RidingProperties {
val seats: List<Seat> = buffer.readList { _ -> Seat.decode(buffer) }
val conditions = buffer.readList { buffer.readString().asExpression() }
val controller = buffer.readNullable { _ ->
val key = buffer.readIdentifier()
val controller = RideControllerAdapter.types[key]?.getConstructor()?.newInstance() ?: error("Unknown controller key: $key")
controller.decode(buffer)
return@readNullable controller
}
return RidingProperties(seats = seats, conditions = conditions, controller = controller)
}
}
val canRide: Boolean
get() = seats.isNotEmpty() && controller != null
fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeCollection(seats) { _, seat -> seat.encode(buffer) }
buffer.writeCollection(conditions) { _, condition -> buffer.writeString(condition.getString()) }
buffer.writeNullable(controller) { _, controller -> controller.encode(buffer) }
}
}
@@ -0,0 +1,18 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding
/**
* Honestly having a base interface is probably unnecessary I'm just considering whether there's going to be some
* kind of shared state later.
*
* @author Hiroku
* @since October 6th, 2024
*/
interface RidingState
@@ -0,0 +1,91 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding
import com.cobblemon.mod.common.api.net.Encodable
import com.cobblemon.mod.common.api.riding.controller.RidingAnimation
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.writeString
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.world.phys.Vec3
/**
* Seat Properties are responsible for the base information that would then be used to construct a Seat on an entity.
*/
data class Seat(
val locator: String = "seat_1",
val offset: Vec3 = Vec3.ZERO,
val poseOffsets: MutableList<SeatPoseOffset> = mutableListOf(),
val poseAnimations: MutableList<SeatPoseAnimations> = mutableListOf()
) : Encodable {
fun getOffset(poseType: PoseType) : Vec3 {
return poseOffsets.firstOrNull { poseType in it.poseTypes }?.offset ?: offset
}
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeString(locator)
buffer.writeDouble(offset.x)
buffer.writeDouble(offset.y)
buffer.writeDouble(offset.z)
buffer.writeCollection(poseOffsets) { _, offset -> offset.encode(buffer) }
buffer.writeCollection(poseAnimations) { _, animations -> animations.encode(buffer) }
}
companion object {
fun decode(buffer: RegistryFriendlyByteBuf) : Seat {
return Seat(
buffer.readString(),
Vec3(buffer.readDouble(), buffer.readDouble(), buffer.readDouble()),
buffer.readList { SeatPoseOffset.decode(buffer) },
buffer.readList { SeatPoseAnimations.decode(buffer) }
)
}
}
}
class SeatPoseOffset {
val poseTypes = mutableSetOf<PoseType>()
var offset = Vec3.ZERO
fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeCollection(poseTypes) { _, poseType -> buffer.writeString(poseType.name) }
buffer.writeDouble(offset.x)
buffer.writeDouble(offset.y)
buffer.writeDouble(offset.z)
}
companion object {
fun decode(buffer: RegistryFriendlyByteBuf) : SeatPoseOffset {
val offset = SeatPoseOffset()
offset.poseTypes.addAll(buffer.readList { buffer.readString().let { PoseType.valueOf(it) } })
offset.offset = Vec3(buffer.readDouble(), buffer.readDouble(), buffer.readDouble())
return offset
}
}
}
class SeatPoseAnimations {
val poseTypes = mutableSetOf<PoseType>()
var animations = mutableListOf<RidingAnimation>()
fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeCollection(poseTypes) { _, poseType -> buffer.writeString(poseType.name) }
buffer.writeCollection(animations) { _, animation -> animation.encode(buffer) }
}
companion object {
fun decode(buffer: RegistryFriendlyByteBuf) : SeatPoseAnimations {
val animations = SeatPoseAnimations()
animations.poseTypes.addAll(buffer.readList { buffer.readString().let { PoseType.valueOf(it) } })
animations.animations = buffer.readList { RidingAnimation.decode(buffer) }
return animations
}
}
}
@@ -0,0 +1,103 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding.controller
import com.cobblemon.mod.common.api.net.Decodable
import com.cobblemon.mod.common.api.net.Encodable
import com.cobblemon.mod.common.api.riding.RidingState
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.writeIdentifier
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
/**
* A riding controller is the internal control mechanism for determining how a pokemon
* handles during riding. Controllers come into play once the pokemon being ridden has
* established the path it's capable of. For instance, a land based controller could have
* the pokemon experience drifting after movement, or generic movement. It's up to the
* controller to decide how the pokemon behaves.
*
* @since x.x.x
*/
interface RideController : Encodable, Decodable {
/** A reference key used to denote the individual controller */
val key: ResourceLocation
/**
* Specifies the provider of poses which helps control updating the current pose on the pokemon
* being ridden. Controllers are expected to define the pose types responsible for posing the entity
* through all expected conditions. It should define a default pose, that will be used in all cases
* where a pose does not meet the current conditions for the current mount. Typically, this will be
* an idle pose.
*/
val poseProvider: PoseProvider
/**
* Represents a condition that must be met for this controller to be active. For instance, this can be used
* to evaluate things such as current velocity or block state of the entity.
*/
val condition: (PokemonEntity) -> Boolean
/**
* Specifies the pose the ridden mount should be positioned in. This queries the pose provider using
* the entity as a means of determining the conditions the entity is currently under. This allows for
* dynamic pose updates.
*/
fun pose(entity: PokemonEntity) : PoseType {
return this.poseProvider.select(entity)
}
/**
* Calculates the current speed of the mount.
*/
fun speed(entity: PokemonEntity, driver: Player) : Float
/**
* Sets the rotation of the mount. This is typically based on the controlling driver and is manipulated as
* necessary.
*/
fun rotation(entity: PokemonEntity, driver: LivingEntity) : Vec2
fun clampPassengerRotation(entity: PokemonEntity, driver: LivingEntity) {}
fun updatePassengerRotation(entity: PokemonEntity, driver: LivingEntity) {
driver.yRot = entity.yRot
}
/**
* Manipulates the movement input as necessary by the controller. This is primarily used to apply limits
* to the types of movements. For instance, we can apply limits to any sort of sideways movement input, so that
* it would otherwise be slower than normal forward movement.
*/
fun velocity(entity: PokemonEntity, driver: Player, input: Vec3) : Vec3
fun canJump(entity: PokemonEntity, driver: Player) : Boolean
fun jumpForce(entity: PokemonEntity, driver: Player, jumpStrength: Int) : Vec3
fun gravity(entity: PokemonEntity, regularGravity: Double) : Double? = null
fun shouldRoll(entity: PokemonEntity): Boolean = false
fun getRuntime(entity: PokemonEntity) = entity.riding.runtime
fun <T : RidingState> getState(entity: PokemonEntity, constructor: (PokemonEntity) -> T): T {
return entity.riding.getState(key, constructor)
}
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeIdentifier(this.key)
}
}
@@ -0,0 +1,32 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding.controller
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.writeString
import net.minecraft.network.RegistryFriendlyByteBuf
class RidingAnimation(
val fileName: String,
val animationName: String
) {
fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeString(fileName)
buffer.writeString(animationName)
}
companion object {
fun decode(buffer: RegistryFriendlyByteBuf) : RidingAnimation {
return RidingAnimation(
buffer.readString(),
buffer.readString()
)
}
}
}
@@ -0,0 +1,15 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding.controller.posing
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import java.util.function.Predicate
data class PoseOption(val pose: PoseType, val condition: Predicate<PokemonEntity>)
@@ -0,0 +1,31 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding.controller.posing
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
class PoseProvider(private val fallback: PoseType) {
private val options = mutableListOf<PoseOption>()
fun select(entity: PokemonEntity) : PoseType {
return this.options.stream()
.filter { it.condition.test(entity) }
.map { it.pose }
.findFirst()
.orElse(this.fallback)
}
fun with(option: PoseOption) : PoseProvider {
this.options.add(option)
return this
}
}
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding.events
import net.minecraft.world.entity.LivingEntity
data class SelectDriverEvent(val options: Set<LivingEntity>) {
private var result: DriverSuggestion? = null
fun result(): LivingEntity? {
return this.result?.entity
}
/**
* Suggests a particular living entity as a potential driver. Only non-negative
* values are permitted by this function. All priority values with lesser priorities
* will be outright ignored.
*/
fun suggest(target: LivingEntity, priority: Int) {
if (priority >= 0 && priority > (this.result?.priority ?: -1)) {
this.result = DriverSuggestion(target, priority)
}
}
data class DriverSuggestion(val entity: LivingEntity, val priority: Int)
}
@@ -498,7 +498,7 @@ class LookAtDirection : ParticleCameraMode {
rotation.hamiltonProduct(Axis.ZP.rotationDegrees(particleAngle))
// Minecraft in 1.21 or 1.20.4 or something fucked with vertex draw order, and it flipped everything.
rotation.hamiltonProduct(Axis.YP.rotationDegrees(180F))
rotation.hamiltonProduct(Axis.XP.rotationDegrees(180F))
return rotation
}
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.api.spawning.rules.component
import com.bedrockk.molang.Expression
import com.bedrockk.molang.ast.BooleanExpression
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
@@ -33,7 +34,7 @@ class FilterRuleComponent : SpawnRuleComponent {
val spawnSelector: SpawnDetailSelector = AllSpawnDetailSelector
val contextSelector: SpawningContextSelector = AllSpawningContextSelector
val allow: Expression = BooleanExpression(true)
val allow: Expression = BooleanExpression(false)
override fun affectSpawnable(detail: SpawnDetail, ctx: SpawningContext): Boolean {
return if (spawnSelector.selects(detail) && contextSelector.selects(ctx)) {
@@ -46,16 +46,16 @@ open class JSONStoreAdapter(
override fun <E, T : PokemonStore<E>> load(file: File, storeClass: Class<out T>, uuid: UUID, registryAccess: RegistryAccess): T? {
return try {
val br = BufferedReader(FileReader(file))
val json = gson.fromJson<JsonObject>(br)
br.close()
val store = try {
storeClass.getConstructor(UUID::class.java, UUID::class.java).newInstance(uuid, uuid)
} catch (exception: NoSuchMethodException) {
storeClass.getConstructor(UUID::class.java).newInstance(uuid)
file.reader().use {
val json = gson.fromJson<JsonObject>(it)
val store = try {
storeClass.getConstructor(UUID::class.java, UUID::class.java).newInstance(uuid, uuid)
} catch (exception: NoSuchMethodException) {
storeClass.getConstructor(UUID::class.java).newInstance(uuid)
}
store.loadFromJSON(json, registryAccess)
store
}
store.loadFromJSON(json, registryAccess)
store
} catch (e: Exception) {
null
}
@@ -42,6 +42,7 @@ abstract class OneToOneFileStoreAdapter<S>(
) : FileStoreAdapter<S>, CobblemonAdapterParent<S>() {
abstract fun save(file: File, serialized: S)
abstract fun <E, T : PokemonStore<E>> load(file: File, storeClass: Class<out T>, uuid: UUID, registryAccess: RegistryAccess): T?
fun getFile(storeClass: Class<out PokemonStore<*>>, uuid: UUID): File {
val className = storeClass.simpleName.lowercase()
val subfolder1 = if (folderPerClass) "$className/" else ""
@@ -56,34 +57,54 @@ abstract class OneToOneFileStoreAdapter<S>(
override fun save(storeClass: Class<out PokemonStore<*>>, uuid: UUID, serialized: S) {
val file = getFile(storeClass, uuid)
val tempFile = File(file.absolutePath + ".temp")
val oldFile = File(file.absolutePath + ".old")
tempFile.createNewFile()
save(tempFile, serialized)
if (file.exists()) {
file.copyTo(oldFile, overwrite = true)
}
tempFile.copyTo(file, overwrite = true)
tempFile.delete()
}
override fun <E : StorePosition, T : PokemonStore<E>> provide(storeClass: Class<T>, uuid: UUID, registryAccess: RegistryAccess): T? {
val file = getFile(storeClass, uuid)
val tempFile = File(file.absolutePath + ".temp")
if (tempFile.exists()) {
try {
val tempLoaded = load(tempFile, storeClass, uuid, registryAccess)
if (tempLoaded != null) {
save(file, serialize(tempLoaded, registryAccess))
return tempLoaded
}
} finally {
tempFile.delete()
}
}
val oldFile = File(file.absolutePath + ".old")
return if (file.exists()) {
return if (file.exists() && file.length() > 0L) {
load(file, storeClass, uuid, registryAccess)
?: let {
LOGGER.error("Pokémon save file for ${storeClass.simpleName} ($uuid) was corrupted. A fresh file will be created.")
storeClass.getConstructor(UUID::class.java).newInstance(uuid)
file.delete()
if (oldFile.exists() && oldFile.length() > 0L) {
var result = load(oldFile, storeClass, uuid, registryAccess) ?: let {
LOGGER.error("Pokémon save file for ${storeClass.simpleName} ($uuid) was corrupted. A fresh file will be created.")
var result = storeClass.getConstructor(UUID::class.java).newInstance(uuid)
save(storeClass, uuid, serialize(result, registryAccess))
oldFile.delete()
return result
}
LOGGER.warn("Loading old Pokémon save file for ${storeClass.simpleName} ($uuid) due to corruption of current file.")
oldFile.copyTo(file, overwrite = true)
result
}
else {
storeClass.getConstructor(UUID::class.java).newInstance(uuid)
var result = storeClass.getConstructor(UUID::class.java).newInstance(uuid)
save(storeClass, uuid, serialize(result, registryAccess))
oldFile.delete()
result
}
}
} else {
file.delete()
if (oldFile.exists() && oldFile.length() > 0L) {
var result = load(oldFile, storeClass, uuid, registryAccess) ?: let {
oldFile.delete()
return null
}
oldFile.copyTo(file, overwrite = true)
result
}
null
}
}
@@ -8,10 +8,12 @@
package com.cobblemon.mod.common.api.storage.player.adapter
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.storage.player.InstancedPlayerData
import com.cobblemon.mod.common.api.storage.player.PlayerInstancedDataStoreType
import net.minecraft.server.MinecraftServer
import net.minecraft.world.level.storage.LevelResource
import java.io.File
import java.nio.file.Path
import java.util.UUID
@@ -35,15 +37,70 @@ abstract class FileBasedPlayerDataStoreBackend<T : InstancedPlayerData>(
savePath = server.getWorldPath(LevelResource.PLAYER_DATA_DIR).parent
}
//TODO: Set file extension to be a field
fun getSubFile(uuid: UUID): String {
return if (useNestedStructure) {
"${uuid.toString().substring(0, 2)}/$uuid.$fileExt"
protected fun postSaveFileMoving(playerData: T) {
val tempFile = filePath(playerData.uuid, TEMPORARY_FILE_EXTENSION)
val oldFile = filePath(playerData.uuid, OLD_FILE_EXTENSION)
val file = filePath(playerData.uuid)
if (file.exists()) {
file.copyTo(oldFile, overwrite = true)
}
tempFile.copyTo(file, overwrite = true)
tempFile.delete()
}
protected fun loadWithFallback(uuid: UUID, loadFunction: (File) -> T): T {
val playerFile = filePath(uuid)
val playerFileOld = filePath(uuid, OLD_FILE_EXTENSION)
playerFile.parentFile.mkdirs()
val loadFallback: () -> T = {
playerFile.delete()
if (playerFileOld.exists() && playerFileOld.length() > 0L) {
try {
var result = loadFunction(playerFileOld)
playerFileOld.copyTo(playerFile)
Cobblemon.LOGGER.debug("Loaded .old {} for {}", subfolder, uuid)
result
} catch (e: Exception) {
Cobblemon.LOGGER.error("Failed to load .old $subfolder for $uuid due to ${e.message}. Data is lost")
Cobblemon.LOGGER.error(e)
playerFileOld.delete()
defaultData.invoke(uuid).also(::save)
}
}
else {
Cobblemon.LOGGER.error(".old File $subfolder for $uuid is corrupt or missing. Data is lost")
playerFileOld.delete()
defaultData.invoke(uuid).also(::save)
}
}
return if (playerFile.exists() && playerFile.length() > 0L) {
try {
loadFunction(playerFile)
}
catch (e: Exception) {
Cobblemon.LOGGER.warn("Failed to load $subfolder for $uuid due to ${e.message}")
Cobblemon.LOGGER.warn(e)
loadFallback()
}
} else {
"$uuid.$fileExt"
loadFallback()
}.also { it.initialize() }
}
@JvmOverloads
fun getSubFile(uuid: UUID, extension: String? = null): String {
return if (useNestedStructure) {
"${uuid.toString().substring(0, 2)}/$uuid.$fileExt${if (extension != null) ".$extension" else ""}"
} else {
"$uuid.$fileExt.${if (extension != null) ".$extension" else ""}"
}
}
fun filePath(uuid: UUID) = savePath.resolve("$subfolder/${getSubFile(uuid)}").toFile()
@JvmOverloads
fun filePath(uuid: UUID, extension: String? = null): File = savePath.resolve("$subfolder/${getSubFile(uuid, extension)}").toFile()
companion object {
const val OLD_FILE_EXTENSION = "old"
const val TEMPORARY_FILE_EXTENSION = "tmp"
}
}
@@ -28,29 +28,26 @@ abstract class JsonBackedPlayerDataStoreBackend<T : InstancedPlayerData>(
abstract val classToken: TypeToken<T>
override fun save(playerData: T) {
val file = filePath(playerData.uuid)
file.parentFile.mkdirs()
val pw = PrintWriter(filePath(playerData.uuid))
pw.write(gson.toJson(playerData))
pw.flush()
pw.close()
val fileTmp = filePath(playerData.uuid, TEMPORARY_FILE_EXTENSION)
fileTmp.parentFile.mkdirs()
fileTmp.printWriter().use { pw ->
pw.write(gson.toJson(playerData))
}
postSaveFileMoving(playerData)
}
override fun load(uuid: UUID): T {
val playerFile = filePath(uuid)
playerFile.parentFile.mkdirs()
return if (playerFile.exists() && playerFile.length() > 0L) {
gson.fromJson(BufferedReader(FileReader(playerFile)), classToken).also {
// Resolves old data that's missing new properties
val newProps = it::class.memberProperties.filterIsInstance<KMutableProperty<*>>().filter { member -> member.getter.call(it) == null }
if (newProps.isNotEmpty()) {
val defaultData = defaultData(uuid)
newProps.forEach { member -> member.setter.call(it, member.getter.call(defaultData)) }
return loadWithFallback(uuid) {
it.reader().use { reader ->
gson.fromJson(reader, classToken).also {
// Resolves old data that's missing new properties
val newProps = it::class.memberProperties.filterIsInstance<KMutableProperty<*>>().filter { member -> member.getter.call(it) == null }
if (newProps.isNotEmpty()) {
val defaultData = defaultData(uuid)
newProps.forEach { member -> member.setter.call(it, member.getter.call(defaultData)) }
}
}
}
} else {
defaultData.invoke(uuid).also(::save)
}.also { it.initialize() }
}
}
}
@@ -24,29 +24,24 @@ abstract class NbtBackedPlayerData<T : InstancedPlayerData>(
type: PlayerInstancedDataStoreType
) : FileBasedPlayerDataStoreBackend<T>(subfolder, type, "nbt") {
abstract val codec: Codec<T>
override fun save(playerData: T) {
val file = filePath(playerData.uuid)
file.parentFile.mkdirs()
val os = DataOutputStream(FileOutputStream(filePath(playerData.uuid)))
val encodeResult = NbtOps.INSTANCE.withEncoder(codec).apply(playerData)
NbtIo.write(encodeResult.result().get() as CompoundTag, os)
os.flush()
os.close()
val fileTmp = filePath(playerData.uuid, TEMPORARY_FILE_EXTENSION)
fileTmp.parentFile.mkdirs()
val encodeResult = codec.encodeStart(NbtOps.INSTANCE, playerData)
NbtIo.write(encodeResult.result().get() as CompoundTag, fileTmp.toPath())
postSaveFileMoving(playerData)
}
override fun load(uuid: UUID): T {
val playerFile = filePath(uuid)
playerFile.parentFile.mkdirs()
return if (playerFile.exists() && playerFile.length() > 0L) {
val input = NbtIo.read(playerFile.toPath())
val decodeResult = NbtOps.INSTANCE.withDecoder(codec).apply(input)
decodeResult.getPartialOrThrow {
return loadWithFallback(uuid) {
val input = NbtIo.read(it.toPath())
val decodeResult = codec.decode(NbtOps.INSTANCE, input)
decodeResult.getOrThrow {
Cobblemon.LOGGER.error("Error decoding $subfolder for player uuid $uuid")
Cobblemon.LOGGER.error(it)
throw UnsupportedOperationException()
}.first
} else {
defaultData.invoke(uuid).also(::save)
}.also { it.initialize() }
}
}
}
@@ -68,6 +68,8 @@ class WinInstruction(val message: BattleMessage): InterpreterInstruction {
}
}
battle.dispatchGo {
battle.winners = winners
battle.losers = losers
battle.end()
CobblemonEvents.BATTLE_VICTORY.post(BattleVictoryEvent(battle, winners, losers, wasCaught))
ShowdownInterpreter.lastCauser.remove(battle.battleId)
@@ -372,24 +372,24 @@ class PokemonClientDelegate : PosableState(), PokemonSideDelegate {
override fun tick(entity: PokemonEntity) {
incrementAge(entity)
if(currentEntity.ownerUUID == null && currentEntity.pokemon.shiny && secondsSinceLastShinyParticle > SHINY_PARTICLE_COOLDOWN && !currentEntity.isBattling) {
//wild shiny not looked at
playShinyEffect("cobblemon:shiny_sparkle_ambient_wild")
lastShinyParticle = System.currentTimeMillis()
}
getClientShinyPokemon()
playWildShinySounds()
}
fun getClientShinyPokemon() {
fun playWildShinySounds() {
val player = Minecraft.getInstance().player ?: return
val isWithinRange = player.position().distanceTo(currentEntity.position()) <= Cobblemon.config.shinyNoticeParticlesDistance
if (currentEntity.pokemon.shiny && currentEntity.ownerUUID == null && !player.isSpectator ) {
if (isWithinRange && !shined) {
playShinyEffect("cobblemon:wild_shiny_ring")
shined = true
lastShinyParticle = System.currentTimeMillis()
} else if (!isWithinRange) {
if (currentEntity.pokemon.shiny && currentEntity.ownerUUID == null) {
if (isWithinRange) {
if (secondsSinceLastShinyParticle > SHINY_PARTICLE_COOLDOWN && !currentEntity.isBattling) {
playShinyEffect("cobblemon:shiny_sparkle_ambient_wild")
lastShinyParticle = System.currentTimeMillis()
}
if (!shined && !player.isSpectator) {
playShinyEffect("cobblemon:wild_shiny_ring")
shined = true
}
} else {
shined = false
}
}
@@ -191,6 +191,8 @@ class BattleTargetSelection(
matrices.pushPose()
matrices.translate(x + TARGET_WIDTH - (25 / 2.0) - 2, y + 5.0, 0.0)
matrices.scale(2.5F, 2.5F, 1F)
// Grab aspects for right variant
state.currentAspects = battlePokemon.state.currentAspects
drawProfilePokemon(
species = battlePokemon.species.resourceIdentifier,
matrixStack = matrices,
@@ -21,18 +21,18 @@ import com.cobblemon.mod.common.net.messages.server.trade.OfferTradePacket
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.common.collect.ArrayListMultimap
import com.google.common.collect.Multimap
import java.util.UUID
import net.minecraft.client.Minecraft
import net.minecraft.network.chat.Component
import java.util.*
import org.joml.Vector3f
fun createPokemonInteractGui(pokemonID: UUID, canMountShoulder: Boolean): InteractWheelGUI {
fun createPokemonInteractGui(pokemonID: UUID, canMountShoulder: Boolean, canRide: Boolean): InteractWheelGUI {
val mountShoulder = InteractWheelOption(
iconResource = cobblemonResource("textures/gui/interact/icon_shoulder.png"),
tooltipText = "cobblemon.ui.interact.mount.shoulder",
onPress = {
if (canMountShoulder) {
InteractPokemonPacket(pokemonID, true).sendToServer()
InteractPokemonPacket(pokemonID, true, false).sendToServer()
closeGUI()
}
}
@@ -41,15 +41,32 @@ fun createPokemonInteractGui(pokemonID: UUID, canMountShoulder: Boolean): Intera
iconResource = cobblemonResource("textures/gui/interact/icon_held_item.png"),
tooltipText = "cobblemon.ui.interact.give.item",
onPress = {
InteractPokemonPacket(pokemonID, false).sendToServer()
InteractPokemonPacket(pokemonID, false, false).sendToServer()
closeGUI()
}
)
val ride = InteractWheelOption(
iconResource = cobblemonResource("textures/gui/interact/icon_held_item.png"),
tooltipText = "cobblemon.ui.interact.ride",
onPress = {
if (canRide) {
InteractPokemonPacket(pokemonID, false, true).sendToServer()
closeGUI()
}
}
)
val options: Multimap<Orientation, InteractWheelOption> = ArrayListMultimap.create()
options.put(Orientation.TOP_RIGHT, giveItem)
if(canRide) {
options.put(Orientation.BOTTOM_LEFT, ride)
}
if (canMountShoulder) {
options.put(Orientation.TOP_LEFT, mountShoulder)
}
CobblemonEvents.POKEMON_INTERACTION_GUI_CREATION.post(PokemonInteractionGUICreationEvent(pokemonID, canMountShoulder, options))
return InteractWheelGUI(options, Component.translatable("cobblemon.ui.interact.pokemon"))
}
@@ -18,7 +18,7 @@ class GrabbedStorageSlot(
) : StorageSlot(x, y, parent, {}) {
init {
isSelected = true
isSlotSelected = true
}
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
@@ -46,7 +46,7 @@ open class StorageSlot(
private val slotOverlayMoveIconResource = cobblemonResource("textures/gui/pasture/pc_slot_icon_move.png")
}
protected var isSelected = false;
protected var isSlotSelected = false;
override fun playDownSound(soundManager: SoundManager) {
}
@@ -84,7 +84,7 @@ open class StorageSlot(
context.disableScissor()
if (!isSelected) {
if (!isSlotSelected) {
// Ensure elements are not hidden behind Pokémon render
matrices.pushPose()
matrices.translate(0.0, 0.0, 100.0)
@@ -129,7 +129,7 @@ open class StorageSlot(
matrices.translate(0.0, 0.0, 500.0)
val config = parent.pcGui.configuration
if (pokemon.tetheringId != null && !isSelected) {
if (pokemon.tetheringId != null && !isSlotSelected) {
if (isStationary()) {
blitk(
matrixStack = matrices,
@@ -163,8 +163,8 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
},
text = lang("ui.evolve"),
resource = evolveButtonResource,
renderRequirement = { selectedPokemon.evolutionProxy.client().isNotEmpty() },
clickRequirement = { selectedPokemon.evolutionProxy.client().isNotEmpty() }
renderRequirement = { selectedPokemon.evolutionProxy.client().isNotEmpty() && CobblemonClient.battle == null },
clickRequirement = { selectedPokemon.evolutionProxy.client().isNotEmpty() && CobblemonClient.battle == null }
)
)
@@ -15,6 +15,6 @@ import net.minecraft.client.Minecraft
object InteractPokemonUIPacketHandler: ClientNetworkPacketHandler<InteractPokemonUIPacket> {
override fun handle(packet: InteractPokemonUIPacket, client: Minecraft) {
client.setScreen(createPokemonInteractGui(packet.pokemonID, packet.canMountShoulder))
client.setScreen(createPokemonInteractGui(packet.pokemonID, packet.canMountShoulder, packet.canRide))
}
}
@@ -51,7 +51,7 @@ open class BedrockActiveAnimation(
headPitch: Float,
intensity: Float
): Boolean {
return animation.run(context, model, state, state.animationSeconds - startedSeconds, limbSwing, limbSwingAmount, ageInTicks, intensity).also {
return animation.run(model, state, state.animationSeconds - startedSeconds, limbSwing, limbSwingAmount, ageInTicks, intensity).also {
if (!it) {
afterAction(context, state)
}
@@ -14,15 +14,17 @@ import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.snowstorm.BedrockParticleOptions
import com.cobblemon.mod.common.client.particle.ParticleStorm
import com.cobblemon.mod.common.client.render.MatrixWrapper
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Bone
import com.cobblemon.mod.common.client.render.models.blockbench.repository.RenderContext
import com.cobblemon.mod.common.util.effectiveName
import com.cobblemon.mod.common.util.genericRuntime
import com.cobblemon.mod.common.util.getString
import com.cobblemon.mod.common.util.math.geometry.toRadians
import com.cobblemon.mod.common.util.resolveDouble
import java.util.SortedMap
import java.util.TreeMap
import net.minecraft.CrashReport
import net.minecraft.ReportedException
import net.minecraft.client.Minecraft
@@ -33,8 +35,6 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.sounds.SoundEvent
import net.minecraft.world.entity.Entity
import net.minecraft.world.phys.Vec3
import org.joml.Matrix4f
import java.util.*
data class BedrockAnimationGroup(
val formatVersion: String,
@@ -149,7 +149,40 @@ data class BedrockAnimation(
/** Useful to have, gets set after loading the animation. */
var name: String = ""
fun run(context: RenderContext, model: PosableModel, state: PosableState, animationSeconds: Float, limbSwing: Float, limbSwingAmount: Float, ageInTicks: Float, intensity: Float): Boolean {
fun run(
model: PosableModel,
state: PosableState,
animationSeconds: Float,
limbSwing: Float,
limbSwingAmount: Float,
ageInTicks: Float,
intensity: Float
): Boolean {
return run(
model.context,
model.relevantPartsByName,
model.rootPart,
state,
animationSeconds,
limbSwing,
limbSwingAmount,
ageInTicks,
intensity
)
}
fun run(
context: RenderContext?,
relevantPartsByName: Map<String, ModelPart>,
rootPart: Bone?,
state: PosableState,
animationSeconds: Float,
limbSwing: Float,
limbSwingAmount: Float,
ageInTicks: Float,
intensity: Float
): Boolean {
var animationSeconds = animationSeconds
if (shouldLoop) {
animationSeconds %= animationLength.toFloat()
@@ -164,7 +197,7 @@ data class BedrockAnimation(
runtime.environment.setSimpleVariable("age_in_ticks", DoubleValue(ageInTicks.toDouble()))
boneTimelines.forEach { (boneName, timeline) ->
val part = model.relevantPartsByName[boneName] ?: if (boneName == "root_part") (model.rootPart as ModelPart) else null
val part = relevantPartsByName[boneName] ?: if (boneName == "root_part") (rootPart as? ModelPart) else null
if (part !== null) {
if (!timeline.position.isEmpty()) {
val position = timeline.position.resolve(animationSeconds.toDouble(), runtime).scale(intensity.toDouble())
@@ -184,7 +217,7 @@ data class BedrockAnimation(
zRot += rotation.z.toFloat().toRadians()
}
} catch (e: Exception) {
val exception = IllegalStateException("Bad animation for entity: ${(model.context.request(RenderContext.ENTITY))!!.effectiveName().string}", e)
val exception = IllegalStateException("Bad animation for entity: ${(context?.request(RenderContext.ENTITY))?.effectiveName()?.string ?: "unknown entity (riding animation?)"}", e)
val crash = CrashReport("Cobblemon encountered an unexpected crash", exception)
val section = crash.addCategory("Animation Details")
section.setDetail("Pose", state.currentPose!!)
@@ -34,7 +34,7 @@ class BedrockPoseAnimation(val animation: BedrockAnimation) : PoseAnimation() {
}
override fun setupAnim(context: RenderContext, model: PosableModel, state: PosableState, limbSwing: Float, limbSwingAmount: Float, ageInTicks: Float, headYaw: Float, headPitch: Float, intensity: Float) {
animation.run(context, model, state, state.animationSeconds, limbSwing, limbSwingAmount, ageInTicks, intensity)
animation.run(model, state, state.animationSeconds, limbSwing, limbSwingAmount, ageInTicks, intensity)
}
override fun applyEffects(entity: Entity?, state: PosableState, previousSeconds: Float, newSeconds: Float) {
@@ -1,106 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.animation.SingleBoneLookAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import com.cobblemon.mod.common.util.isBattling
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class ExeggutorAlolanModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame {
override val rootPart = root.registerChildWithAllChildren("exeggutor")
override val head = getPart("head")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
val head2 = object : HeadedFrame {
override val rootPart = this@ExeggutorAlolanModel.rootPart
override val head: ModelPart = getPart("head2")
}
val head3 = object : HeadedFrame {
override val rootPart = this@ExeggutorAlolanModel.rootPart
override val head: ModelPart = getPart("head3")
}
override var portraitScale = 1.0F
override var portraitTranslation = Vec3(-1.4, 16.55, 0.0)
override var profileScale = 0.45F
override var profileTranslation = Vec3(0.0, 1.0, -30.0)
lateinit var standing: Pose
lateinit var walk: Pose
lateinit var sleep: Pose
lateinit var battleidle: Pose
override fun registerPoses() {
val blink1 = quirk { bedrockStateful("exeggutor_alolan", "blink") }
val blink2 = quirk { bedrockStateful("exeggutor_alolan", "blink2") }
val blink3 = quirk { bedrockStateful("exeggutor_alolan", "blink3") }
val blink4 = quirk { bedrockStateful("exeggutor_alolan", "blink4") }
sleep = registerPose(
poseType = PoseType.SLEEP,
animations = arrayOf(bedrock("exeggutor_alolan", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = STATIONARY_POSES + UI_POSES,
quirks = arrayOf(blink1, blink2, blink3, blink4),
condition = { !it.isBattling },
animations = arrayOf(
singleBoneLook(),
SingleBoneLookAnimation(head2, false, false, disableX = false, disableY = false),
SingleBoneLookAnimation(head3, false, false, disableX = false, disableY = false),
bedrock("exeggutor_alolan", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
quirks = arrayOf(blink1, blink2, blink3, blink4),
animations = arrayOf(
singleBoneLook(),
SingleBoneLookAnimation(head2, false, false, disableX = false, disableY = false),
SingleBoneLookAnimation(head3, false, false, disableX = false, disableY = false),
bedrock("exeggutor_alolan", "ground_walk")
)
)
battleidle = registerPose(
poseName = "battle_idle",
poseTypes = PoseType.STATIONARY_POSES,
transformTicks = 10,
quirks = arrayOf(blink1, blink2, blink3, blink4),
condition = { it.isBattling },
animations = arrayOf(
singleBoneLook(),
SingleBoneLookAnimation(head2, false, false, disableX = false, disableY = false),
SingleBoneLookAnimation(head3, false, false, disableX = false, disableY = false),
bedrock("exeggutor_alolan", "battle_idle")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PosableState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("exeggutor_alolan", "faint") else null
}
@@ -28,7 +28,7 @@ class ArctozoltModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame
override var portraitTranslation = Vec3(-0.45, 2.15, 0.0)
override var portraitScale = 0.85F
override var profileTranslation = Vec3(0.02, 0.95, 0.0)
override var profileTranslation = Vec3(0.02, 1.14, 0.0)
override var profileScale = 0.33F
lateinit var sleep: CobblemonPose
@@ -51,7 +51,9 @@ class CharcadetModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame,
val blink = quirk { bedrockStateful("charcadet", "blink") }
sleep = registerPose(
poseType = PoseType.SLEEP,
animations = arrayOf(bedrock("charcadet", "sleep"))
animations = arrayOf(bedrock("charcadet", "sleep"),
bedrock("charcadet", "eye_flame_overlay"),
bedrock("charcadet", "head_flame_overlay"))
)
standing = registerPose(
@@ -61,7 +63,9 @@ class CharcadetModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("charcadet", "ground_idle")
bedrock("charcadet", "ground_idle"),
bedrock("charcadet", "eye_flame_overlay"),
bedrock("charcadet", "head_flame_overlay")
)
)
@@ -72,7 +76,9 @@ class CharcadetModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("charcadet", "ground_walk")
bedrock("charcadet", "ground_walk"),
bedrock("charcadet", "eye_flame_overlay"),
bedrock("charcadet", "head_flame_overlay")
)
)
@@ -81,7 +87,9 @@ class CharcadetModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("charcadet", "shoulder_left")
bedrock("charcadet", "shoulder_left"),
bedrock("charcadet", "eye_flame_overlay"),
bedrock("charcadet", "head_flame_overlay")
),
transformedParts = arrayOf(
rootPart.createTransformation().addPosition(ModelPartTransformation.Y_AXIS, -0.1),
@@ -94,7 +102,9 @@ class CharcadetModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("charcadet", "shoulder_right")
bedrock("charcadet", "shoulder_right"),
bedrock("charcadet", "eye_flame_overlay"),
bedrock("charcadet", "head_flame_overlay")
),
transformedParts = arrayOf(
rootPart.createTransformation().addPosition(ModelPartTransformation.Y_AXIS, -0.1),
@@ -90,7 +90,6 @@ object PokemonModelRepository : VaryingModelRepository<PokemonPosableModel>() {
inbuilt("electabuzz", ::ElectabuzzModel)
inbuilt("exeggcute", ::ExeggcuteModel)
inbuilt("exeggutor", ::ExeggutorModel)
inbuilt("exeggutor_alolan", ::ExeggutorAlolanModel)
inbuilt("farfetchd", ::FarfetchdModel)
inbuilt("farfetchd_galarian", ::FarfetchdGalarianModel)
inbuilt("fearow", ::FearowModel)
@@ -60,4 +60,11 @@ class NPCRenderer(context: Context) : LivingEntityRenderer<NPCEntity, PosableEnt
// this.renderLabelIfPresent(entity, entity.displayName, poseMatrix, buffer, packedLight)
// }
}
override fun shouldShowName(entity: NPCEntity): Boolean {
if (entity.hideNameTag) {
return false
}
return super.shouldShowName(entity)
}
}
@@ -0,0 +1,108 @@
/*
* 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.player
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animation.BedrockAnimationRepository
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.math.geometry.toRadians
import com.cobblemon.mod.common.util.withPlayerValue
import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.client.Minecraft
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.client.player.AbstractClientPlayer
import net.minecraft.world.phys.Vec3
import org.joml.Matrix4f
import org.joml.Vector3f
/**
* @author landonjw
*/
object MountedPlayerRenderer {
fun render(player: AbstractClientPlayer, entity: PokemonEntity, stack: PoseStack) {
val camera = Minecraft.getInstance().gameRenderer.mainCamera
val yaw = camera.yRot.toRadians()
val isEntityFlying = false
val offset = getOffset(player, entity, isEntityFlying, yaw)
val matrix = stack.last().pose()
if (isEntityFlying) {
val cameraRotation = camera.rotation().get(Matrix4f())
matrix.mul(cameraRotation)
}
matrix.translate(offset)
if (isEntityFlying) matrix.rotateY(yaw)
player.yBodyRot = player.yHeadRot
}
private fun getOffset(
player: AbstractClientPlayer,
entity: PokemonEntity,
isEntityFlying: Boolean,
yaw: Float
): Vector3f {
val seats = entity.seats
val seatIndex = entity.passengers.indexOf(player).takeIf { it != -1 && it < seats.size } ?: return player.position().toVector3f()
val mountOrigin = (entity.delegate as PokemonClientDelegate).locatorStates["seat${seatIndex+1}"]?.getOrigin() ?: return Vector3f()
val playerOrigin = Vec3(player.x, player.y, player.z)
val offsetOrigin = mountOrigin.subtract(playerOrigin).subtract(0.0, 0.6, 0.0)
val offsetMatrix = Matrix4f()
if (isEntityFlying) offsetMatrix.rotateY(yaw)
offsetMatrix.translate(offsetOrigin.toVector3f())
return offsetMatrix.getTranslation(Vector3f())
}
fun animate(
pokemonEntity: PokemonEntity,
player: AbstractClientPlayer,
relevantPartsByName: Map<String, ModelPart>,
headYaw: Float,
headPitch: Float,
ageInTicks: Float,
limbSwing: Float,
limbSwingAmount: Float
) {
val seatIndex = pokemonEntity.passengers.indexOf(player).takeIf { it != -1 && it < pokemonEntity.seats.size } ?: return
val seat = pokemonEntity.seats[seatIndex]
val animations = seat.poseAnimations.firstOrNull { it.poseTypes.isEmpty() || it.poseTypes.contains(pokemonEntity.getCurrentPoseType()) }?.animations
?: return
val state = pokemonEntity.delegate as PokemonClientDelegate
relevantPartsByName.values.forEach {
it.xRot = 0F
it.yRot = 0F
it.zRot = 0F
}
state.runtime.environment.setSimpleVariable("age_in_ticks", DoubleValue(ageInTicks.toDouble()))
state.runtime.environment.setSimpleVariable("limb_swing", DoubleValue(limbSwing.toDouble()))
state.runtime.environment.setSimpleVariable("limb_swing_amount", DoubleValue(limbSwingAmount.toDouble()))
// TODO add the q.player reference, requires a cached thing or something on the client idk
for (animation in animations) {
val bedrockAnimation = BedrockAnimationRepository.getAnimationOrNull(animation.fileName, animation.animationName) ?: continue
bedrockAnimation.run(
context = null,
relevantPartsByName = relevantPartsByName,
rootPart = null,
state = state,
animationSeconds = state.animationSeconds,
limbSwing = limbSwing,
limbSwingAmount = limbSwingAmount,
ageInTicks = ageInTicks,
intensity = 1F
)
}
}
}
@@ -0,0 +1,117 @@
package com.cobblemon.mod.common.client.render.player
import com.cobblemon.mod.common.Rollable
import com.cobblemon.mod.common.api.riding.Rideable
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
import com.cobblemon.mod.common.client.render.ClientPlayerIcon.Companion.onRenderPlayer
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.mixin.PlayerRendererMixin
import com.cobblemon.mod.common.util.math.geometry.toRadians
import com.cobblemon.mod.common.util.math.geometry.transformPosition
import com.cobblemon.mod.common.util.toVec3d
import com.llamalad7.mixinextras.injector.wrapoperation.Operation
import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.client.Minecraft
import net.minecraft.client.player.AbstractClientPlayer
import net.minecraft.client.renderer.LevelRenderer
import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.RenderType
import net.minecraft.util.Mth
import net.minecraft.world.phys.Vec3
import org.joml.AxisAngle4f
import org.joml.Matrix3f
import org.joml.Matrix4f
import org.joml.Quaternionf
import org.joml.Vector3d
import org.joml.Vector3f
import org.joml.Vector4f
object PlayerRendererHook {
var maxPartialTicks = 0F
const val disableRollableRenderDebug: Boolean = false
fun before(
player: AbstractClientPlayer,
entityYaw: Float,
partialTicks: Float,
poseStack: PoseStack,
multiBufferSource: MultiBufferSource,
i: Int
) {
val shouldRoll = player is Rollable && player.shouldRoll()
if (player.vehicle is Rideable) {
//We want to ignore where vanilla is placing the player, so get rid of any transformations that have occured so far
poseStack.setIdentity()
//The actual rendering of the player model expects to be able to use coordinates relative to the camera's position
//So all of our coordinates need to be offset by the camera position
val cameraPos = Minecraft.getInstance().gameRenderer.mainCamera.position
val vehicle = player.vehicle as Rideable
val entity = player.vehicle!!
//Get the seat
val seatIndex = vehicle.riding.entity.passengers.indexOf(player)
val seat = vehicle.riding.entity.seats[seatIndex]
var playerPosition = seat.offset
//If we are riding a posable entity, use the locator position over the seat offset
if (entity is PosableEntity) {
val posableState = entity.delegate as PosableState
val locator = posableState.locatorStates[seat.locator]!!
val locatorOffset = locator.getOrigin().subtract(entity.position())
val oldLocatorPos = locatorOffset.add(Vec3(entity.xOld, entity.yOld, entity.zOld))
val curLocatorPos = oldLocatorPos.lerp(locator.getOrigin(), partialTicks.toDouble()).subtract(cameraPos)
playerPosition = curLocatorPos
}
if (shouldRoll) {
//Here, basically what we are doing is figuring out the coords of the rotated locator.
//We have to do the same rotations that are done in the pokemon renderer
val rollable = player as Rollable
val pokemonCenter = Vec3(entity.xOld, entity.yOld, entity.zOld).lerp(entity.position(), partialTicks.toDouble()).add(0.0, entity.bbHeight / 2.0, 0.0).subtract(cameraPos)
val transformationMatrix = Matrix4f()
transformationMatrix.translate(pokemonCenter.toVector3f())
transformationMatrix.rotate(180f.toRadians() - (rollable.yaw).toRadians(), rollable.upVector, transformationMatrix)
transformationMatrix.rotate((-rollable.pitch).toRadians(), rollable.leftVector, transformationMatrix)
transformationMatrix.rotate((-rollable.roll).toRadians(), rollable.forwardVector, transformationMatrix)
transformationMatrix.translate(pokemonCenter.toVector3f().negate())
playerPosition = transformationMatrix.transformPosition(playerPosition)
//We need to move "down" half a block to account for the player crouching pose.
playerPosition = playerPosition.subtract(Vector3f(rollable.upVector).mul(0.5F).toVec3d())
}
else {
playerPosition = playerPosition.subtract(0.0, 0.5, 0.0)
}
poseStack.translate(playerPosition.x, playerPosition.y, playerPosition.z)
if (shouldRoll) {
val orientation = Matrix4f((player as Rollable).orientation ?: Matrix3f())
val rotation = orientation.getRotation(AxisAngle4f())
poseStack.mulPose(Quaternionf(rotation))
}
}
}
fun renderAxisLines(
player: AbstractClientPlayer,
entityYaw: Float,
partialTicks: Float,
poseStack: PoseStack,
multiBufferSource: MultiBufferSource,
i: Int
) {
if (player is Rollable) {
val pose = poseStack.last().pose()
val buffer = multiBufferSource.getBuffer(RenderType.lines())
//"Forward" is red
val forwardVector = player.forwardVector.mul(2F)
buffer.addVertex(pose, 0F, 0F, 0F).setColor(1F, 0F, 0F, 1F).setNormal(1F, 1F, 1F)
buffer.addVertex(pose, forwardVector.x, forwardVector.y, forwardVector.z).setColor(1F, 0F, 0F, 1F).setNormal(1F, 1F, 1F)
//"Left" is blue
val leftVector = player.leftVector.mul(2F)
buffer.addVertex(pose, 0F, 0F, 0F).setColor(0F, 0F, 1F, 1F).setNormal(1F, 1F, 1F)
buffer.addVertex(pose, leftVector.x, leftVector.y, leftVector.z).setColor(0F, 0F, 1F, 1F).setNormal(1F, 1F, 1F)
//"Up" is green
val upVector = player.upVector.mul(2F)
buffer.addVertex(pose, 0F, 0F, 0F).setColor(0F, 1F, 0F, 1F).setNormal(1F, 1F, 1F)
buffer.addVertex(pose, upVector.x, upVector.y, upVector.z).setColor(0F, 1F, 0F, 1F).setNormal(1F, 1F, 1F)
}
}
}
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.client.render.pokemon
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.Rollable
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.battle.ClientBallDisplay
@@ -41,7 +42,6 @@ import com.cobblemon.mod.common.util.math.geometry.toRadians
import com.cobblemon.mod.common.util.math.remap
import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.math.Axis
import kotlin.math.*
import net.minecraft.ChatFormatting
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.Font.DisplayMode
@@ -57,10 +57,8 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.util.Mth
import net.minecraft.world.entity.Entity
import net.minecraft.world.phys.Vec3
import org.joml.Math
import org.joml.Quaternionf
import org.joml.Vector3f
import org.joml.Vector4f
import org.joml.*
import kotlin.math.*
class PokemonRenderer(
context: EntityRendererProvider.Context
@@ -81,6 +79,7 @@ class PokemonRenderer(
private const val SPACE = " "
private const val DISABLE_ROLLING_DEBUG = false
}
val ballContext = RenderContext().also {
@@ -141,7 +140,12 @@ class PokemonRenderer(
modelNow.setLayerContext(buffer, clientDelegate, PokemonModelRepository.getLayers(entity.pokemon.species.resourceIdentifier, clientDelegate))
super.render(entity, entityYaw, partialTicks, poseMatrix, buffer, packedLight)
if (entity.passengers.isNotEmpty()) {
renderRiding(entity, partialTicks, poseMatrix, buffer, packedLight)
}
else {
super.render(entity, entityYaw, partialTicks, poseMatrix, buffer, packedLight)
}
modelNow.green = 1F
modelNow.blue = 1F
@@ -152,6 +156,43 @@ class PokemonRenderer(
// Minecraft.getInstance().bufferBuilders.entityVertexConsumers.draw()
}
fun renderRiding(
entity: PokemonEntity,
partialTicks: Float,
poseMatrix: PoseStack,
buffer: MultiBufferSource,
packedLight: Int
) {
// TODO: This is all broken at the moment, need to figure out proper way to rotate the model according to camera
val driver = entity.firstPassenger ?: return
val rollable = driver as? Rollable ?: return
poseMatrix.pushPose()
if(!DISABLE_ROLLING_DEBUG && rollable.shouldRoll()){
val yaw = Mth.rotLerp(partialTicks, entity.yBodyRotO, entity.yBodyRot)
val matrix = poseMatrix.last().pose()
val center = Vector3f(0f, entity.bbHeight/2, 0f)
val transformationMatrix = Matrix4f()
transformationMatrix.translate(center)
transformationMatrix.rotate(180f.toRadians() - (rollable.yaw).toRadians(), rollable.upVector, transformationMatrix)
transformationMatrix.rotate((-rollable.pitch).toRadians(), rollable.leftVector, transformationMatrix)
transformationMatrix.rotate((-rollable.roll).toRadians(), rollable.forwardVector, transformationMatrix)
transformationMatrix.translate(center.negate(Vector3f()))
matrix.mul(transformationMatrix)
poseMatrix.mulPose(Axis.YP.rotationDegrees(-(180.0f - yaw)))
}
super.render(entity, 0f, partialTicks, poseMatrix, buffer, packedLight)
poseMatrix.popPose()
}
fun renderTransition(
modelNow: PosableModel,
beamMode: Int,
@@ -457,4 +498,4 @@ class PokemonRenderer(
matrixStack.popPose()
}
}
}
@@ -8,7 +8,9 @@
package com.cobblemon.mod.common.entity
import java.util.EnumSet
import com.cobblemon.mod.common.util.cobblemonResource
import java.util.*
import net.minecraft.resources.ResourceLocation
/**
* The type of a pose. Used for normalizing pose swapping for all models.
@@ -46,5 +48,11 @@ enum class PoseType {
val UI_POSES = EnumSet.of(PROFILE, PORTRAIT)
val MOVING_POSES = EnumSet.of(WALK, SWIM, FLY)
val STATIONARY_POSES = EnumSet.of(STAND, FLOAT, HOVER)
fun identified() : List<ResourceLocation> {
return ALL_POSES.stream()
.map { cobblemonResource(it.name.lowercase(Locale.getDefault())) }
.toList()
}
}
}
@@ -35,6 +35,7 @@ import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import com.cobblemon.mod.common.util.toBlockPos
import com.cobblemon.mod.common.util.weightedSelection
import net.minecraft.advancements.CriteriaTriggers
import net.minecraft.client.resources.sounds.EntityBoundSoundInstance
import net.minecraft.core.BlockPos
@@ -183,33 +184,19 @@ class PokeRodFishingBobberEntity(type: EntityType<out PokeRodFishingBobberEntity
}
fun chooseAdjustedSpawnBucket(buckets: List<SpawnBucket>, luckOfTheSeaLevel: Int): SpawnBucket {
val baseIncreases = listOf(2.5F, 0.5F, 0.2F) // Base increases for the first three buckets beyond the first
val baseValues = listOf(94.3F, 5.0F, 0.5F, 0.2F)
val adjustments = listOf(-4.1F, 2.5F, 1.0F, 0.6F)
val adjustedWeights = buckets.mapIndexed { index, bucket ->
if (index == 0) {
// Placeholder, will be recalculated
0.0F
} else {
val increase = if (index < baseIncreases.size) baseIncreases[index] else baseIncreases.last() + (index - baseIncreases.size + 1) * 0.15F
bucket.weight + increase * luckOfTheSeaLevel
if (index >= baseValues.size) {
return@mapIndexed bucket to bucket.weight
}
}.toMutableList()
val base = baseValues[index]
val adjustment = adjustments[index]
bucket to (base + adjustment * luckOfTheSeaLevel)
}.toMap()
// Recalculate the first bucket's weight to ensure the total is 100%
val totalAdjustedWeight = adjustedWeights.sum() - adjustedWeights[0] // Corrected to ensure the list contains Floats
adjustedWeights[0] = 100.0F - totalAdjustedWeight + buckets[0].weight
// Random selection based on adjusted weights
val weightSum = adjustedWeights.sum()
val chosenSum = kotlin.random.Random.nextDouble(weightSum.toDouble()).toFloat() // Ensure usage of Random from kotlin.random package
var sum = 0.0F
adjustedWeights.forEachIndexed { index, weight ->
sum += weight
if (sum >= chosenSum) {
return buckets[index]
}
}
return buckets.first() // Fallback
return buckets.weightedSelection { adjustedWeights[it]!! }!!
}
fun isOpenOrWaterAround(pos: BlockPos): Boolean {
@@ -335,7 +322,7 @@ class PokeRodFishingBobberEntity(type: EntityType<out PokeRodFishingBobberEntity
val buckets = Cobblemon.bestSpawner.config.buckets
// choose a spawn bucket according to weights no matter how many there are
// choose a spawn bucket according to weights and luck of the sea
chosenBucket = chooseAdjustedSpawnBucket(buckets, luckOfTheSeaLevel)
CobblemonEvents.BOBBER_BUCKET_CHOSEN.post(BobberBucketChosenEvent(chosenBucket, buckets, luckOfTheSeaLevel)) { event ->
chosenBucket = event.chosenBucket
@@ -698,10 +685,9 @@ class PokeRodFishingBobberEntity(type: EntityType<out PokeRodFishingBobberEntity
)
// This has a chance to fail, if the position has no suitability for a fishing context
// it could also just be a miss which
// means two attempts to spawn in the same location can have differing results (which is expected for
// randomness).
if (result == null) {
// it could also just be a miss which means two attempts to spawn in the same location
// can have differing results (which is expected for randomness).
if (result == null || result.isCompletedExceptionally) {
player.sendSystemMessage(lang("fishing.no_bite").red())
return false
}
@@ -109,6 +109,12 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
val level: Int
get() = entityData.get(LEVEL)
var hideNameTag: Boolean
get() = entityData.get(HIDE_NAME_TAG)
set(value) {
entityData.set(HIDE_NAME_TAG, value)
}
var skill: Int? = null // range from 0 - 5
var baseScale: Float? = null
@@ -204,7 +210,7 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
val BATTLE_IDS = SynchedEntityData.defineId(NPCEntity::class.java, UUIDSetDataSerializer)
val NPC_PLAYER_TEXTURE = SynchedEntityData.defineId(NPCEntity::class.java, NPCPlayerTextureSerializer)
val LEVEL = SynchedEntityData.defineId(NPCEntity::class.java, EntityDataSerializers.INT)
val HIDE_NAME_TAG = SynchedEntityData.defineId(NPCEntity::class.java, EntityDataSerializers.BOOLEAN)
// val BATTLING = Activity.register("npc_battling")
@@ -255,6 +261,7 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
builder.define(BATTLE_IDS, setOf())
builder.define(NPC_PLAYER_TEXTURE, NPCPlayerTexture(ByteArray(1), NPCPlayerModelType.NONE))
builder.define(LEVEL, 1)
builder.define(HIDE_NAME_TAG, false)
}
override fun getAddEntityPacket(serverEntity: ServerEntity) = ClientboundCustomPayloadPacket(
@@ -318,6 +325,7 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
nbt.put(DataKeys.NPC_DATA, MoLangFunctions.writeMoValueToNBT(data))
nbt.put(DataKeys.NPC_CONFIG, MoLangFunctions.writeMoValueToNBT(config))
nbt.put(DataKeys.NPC_LEVEL, IntTag.valueOf(level))
nbt.putBoolean(DataKeys.NPC_HIDE_NAME_TAG, hideNameTag)
nbt.putString(DataKeys.NPC_CLASS, npc.id.toString())
nbt.put(DataKeys.NPC_ASPECTS, ListTag().also { list -> appliedAspects.forEach { list.add(StringTag.valueOf(it)) } })
nbt.put(DataKeys.NPC_VARIATION_ASPECTS, ListTag().also { list -> variationAspects.forEach { list.add(StringTag.valueOf(it)) } })
@@ -383,6 +391,7 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
override fun load(nbt: CompoundTag) {
npc = NPCClasses.getByIdentifier(ResourceLocation.parse(nbt.getString(DataKeys.NPC_CLASS))) ?: NPCClasses.classes.first()
entityData.set(LEVEL, nbt.getInt(DataKeys.NPC_LEVEL).takeIf { it != 0 } ?: 1)
entityData.set(HIDE_NAME_TAG, nbt.getBoolean(DataKeys.NPC_HIDE_NAME_TAG))
super.load(nbt)
data = MoLangFunctions.readMoValueFromNBT(nbt.getCompound(DataKeys.NPC_DATA)) as VariableStruct
config = if (nbt.contains(DataKeys.NPC_CONFIG)) MoLangFunctions.readMoValueFromNBT(nbt.getCompound(DataKeys.NPC_CONFIG)) as VariableStruct else VariableStruct()
@@ -490,6 +499,7 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
fun initialize(level: Int) {
variationAspects.clear()
entityData.set(HIDE_NAME_TAG, npc.hideNameTag)
entityData.set(LEVEL, level)
npc.config.forEach { it.applyDefault(this) }
npc.variations.values.forEach { this.variationAspects.addAll(it.provideAspects(this)) }
+215 -17
View File
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.CobblemonEntities
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.Rollable
import com.cobblemon.mod.common.api.drop.DropTable
import com.cobblemon.mod.common.api.entity.Despawner
import com.cobblemon.mod.common.api.entity.PokemonSender
@@ -30,7 +31,6 @@ import com.cobblemon.mod.common.api.molang.ObjectValue
import com.cobblemon.mod.common.api.net.serializers.PlatformTypeDataSerializer
import com.cobblemon.mod.common.api.net.serializers.PoseTypeDataSerializer
import com.cobblemon.mod.common.api.net.serializers.StringSetDataSerializer
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.feature.ChoiceSpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.feature.FlagSpeciesFeature
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
@@ -38,6 +38,10 @@ import com.cobblemon.mod.common.api.pokemon.feature.StringSpeciesFeature
import com.cobblemon.mod.common.api.pokemon.status.Statuses
import com.cobblemon.mod.common.api.reactive.ObservableSubscription
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.api.riding.Rideable
import com.cobblemon.mod.common.api.riding.RidingManager
import com.cobblemon.mod.common.api.riding.Seat
import com.cobblemon.mod.common.api.riding.events.SelectDriverEvent
import com.cobblemon.mod.common.api.scheduling.Schedulable
import com.cobblemon.mod.common.api.scheduling.SchedulingTracker
import com.cobblemon.mod.common.api.scheduling.afterOnServer
@@ -80,12 +84,12 @@ import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolut
import com.cobblemon.mod.common.pokemon.feature.StashHandler
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
import com.cobblemon.mod.common.util.*
import com.cobblemon.mod.common.util.math.geometry.toRadians
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
import com.mojang.serialization.Codec
import java.util.EnumSet
import java.util.Optional
import java.util.UUID
import java.util.*
import java.util.concurrent.CompletableFuture
import kotlin.math.PI
import net.minecraft.core.BlockPos
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
@@ -111,7 +115,6 @@ import net.minecraft.sounds.SoundEvents
import net.minecraft.sounds.SoundSource
import net.minecraft.tags.FluidTags
import net.minecraft.util.Mth
import net.minecraft.util.Mth.clamp
import net.minecraft.world.InteractionHand
import net.minecraft.world.InteractionResult
import net.minecraft.world.damagesource.DamageSource
@@ -143,14 +146,17 @@ import net.minecraft.world.level.gameevent.GameEvent
import net.minecraft.world.level.material.FluidState
import net.minecraft.world.level.pathfinder.PathType
import net.minecraft.world.phys.AABB
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
import org.joml.Matrix3f
import org.joml.Vector3f
@Suppress("unused")
open class PokemonEntity(
world: Level,
pokemon: Pokemon = Pokemon().apply { isClient = world.isClientSide },
type: EntityType<out PokemonEntity> = CobblemonEntities.POKEMON,
) : ShoulderRidingEntity(type, world), PosableEntity, Shearable, Schedulable, ScannableEntity {
) : ShoulderRidingEntity(type, world), PosableEntity, Shearable, Schedulable, Rideable, ScannableEntity {
companion object {
@JvmStatic val SPECIES = SynchedEntityData.defineId(PokemonEntity::class.java, EntityDataSerializers.STRING)
@JvmStatic val NICKNAME = SynchedEntityData.defineId(PokemonEntity::class.java, EntityDataSerializers.COMPONENT)
@@ -178,7 +184,7 @@ open class PokemonEntity(
const val BATTLE_LOCK = "battle"
const val EVOLUTION_LOCK = "evolving"
fun createAttributes(): AttributeSupplier.Builder = LivingEntity.createLivingAttributes()
fun createAttributes(): AttributeSupplier.Builder = createLivingAttributes()
.add(Attributes.FOLLOW_RANGE)
.add(Attributes.ATTACK_KNOCKBACK)
}
@@ -228,6 +234,8 @@ open class PokemonEntity(
get() = entityData.get(BATTLE_ID).isPresent
val friendship: Int
get() = entityData.get(FRIENDSHIP)
val seats: List<Seat>
get() = form.riding.seats
var drops: DropTable? = null
@@ -237,6 +245,8 @@ open class PokemonEntity(
var enablePoseTypeRecalculation = true
override val riding: RidingManager = RidingManager(this)
/**
* The amount of steps this entity has traveled.
*/
@@ -340,7 +350,7 @@ open class PokemonEntity(
SPECIES -> refreshDimensions()
POSE_TYPE -> {
val value = entityData.get(data) as PoseType
if (value == PoseType.FLY || value == PoseType.HOVER) {
if ((value == PoseType.FLY || value == PoseType.HOVER) && passengers.isEmpty()) {
setNoGravity(true)
} else {
setNoGravity(false)
@@ -450,6 +460,9 @@ open class PokemonEntity(
this.tethering = null
this.pokemon.recall()
}
jumping = false
//This is so that pokemon in the pasture block are ALWAYS in sync with the pokemon box
//Before, pokemon entities in pastures would hold an old ref to a pokemon obj and changes to that would not appear to the underlying file
if (this.tethering != null && age % 20 == 0) {
@@ -522,10 +535,6 @@ open class PokemonEntity(
return super.isInvulnerableTo(damageSource)
}
override fun canRide(vehicle: Entity): Boolean {
return platform == PlatformType.NONE && super.canRide(vehicle)
}
/**
* A utility method that checks if this Pokémon has the [UncatchableProperty.uncatchable] property.
*
@@ -928,7 +937,7 @@ open class PokemonEntity(
if (hand == InteractionHand.MAIN_HAND && player is ServerPlayer && pokemon.getOwnerPlayer() == player) {
if (player.isShiftKeyDown) {
InteractPokemonUIPacket(this.getUUID(), canSitOnShoulder() && pokemon in player.party()).sendToPlayer(
InteractPokemonUIPacket(this.getUUID(), canSitOnShoulder() && pokemon in player.party(), this.canRide(player)).sendToPlayer(
player
)
} else {
@@ -1432,8 +1441,7 @@ open class PokemonEntity(
*
* @return If the backing [pokemon] has a non-null [Pokemon.nickname].
*/
override fun hasCustomName(): Boolean =
pokemon.nickname != null && pokemon.nickname?.contents != PlainTextContents.EMPTY
override fun hasCustomName(): Boolean = pokemon.nickname != null && pokemon.nickname?.contents != PlainTextContents.EMPTY
/**
* This method toggles the visibility of the entity name,
@@ -1557,6 +1565,9 @@ open class PokemonEntity(
}
override fun canBeLeashed() = true
// override fun canBeLeashedBy(player: Player): Boolean {
// return this.ownerUuid == null || this.ownerUuid == player.uuid
// }
override fun setLeashedTo(entity: Entity, bl: Boolean) {
super.setLeashedTo(entity, bl)
@@ -1575,6 +1586,194 @@ open class PokemonEntity(
*/
private fun createSidedPokemon(): Pokemon = Pokemon().apply { isClient = this@PokemonEntity.level().isClientSide }
override fun canRide(entity: Entity): Boolean {
return platform == PlatformType.NONE && super.canRide(entity)
}
override fun canAddPassenger(passenger: Entity): Boolean {
return passengers.size < seats.size
}
fun getIsJumping() = jumping
fun setIsJumping(value: Boolean) {
jumping = value
}
override fun tickRidden(driver: Player, movementInput: Vec3) {
super.tickRidden(driver, movementInput)
this.riding.tick(this, driver, movementInput)
val rotation = this.getControlledRotation(driver)
setRot(rotation.y, rotation.x)
this.yHeadRot = this.yRot
this.yBodyRot = this.yRot
this.yRotO = this.yRot
if (this.riding.canJump(this, driver)) {
if (this.onGround()) {
if (this.jumpInputStrength > 0) {
// this.jump(this.jumpStrength, movementInput)
// this.jump()
val f = PI.toFloat() - this.yRot * PI.toFloat() / 180
val jumpVector = riding.jumpVelocity(this, driver, this.jumpInputStrength)
val velocity = jumpVector.yRot(f)
// Rotate the jump vector f degrees around the Y axis
// val velocity = Vec3d(-sin(f) * jumpVector.x, jumpVector.y, cos(f) * jumpVector.z)
this.addDeltaMovement(velocity)
hasImpulse = true
jumping = false
}
this.jumpInputStrength = 0
}
}
// val lookAngle: Vec3 = driver.getLookAngle()
// if (!driver.isNearGround() || lookAngle.y >= 0.3) {
// setBehaviourFlag(PokemonBehaviourFlag.FLYING, true)
// entityData.set(POSE_TYPE, PoseType.HOVER)
//
// val deltaMovement = this.deltaMovement
// this.setDeltaMovement(
// lookAngle.x * 0.1 + (lookAngle.x * 1.5 - deltaMovement.x) * 1,
// lookAngle.y * 0.1 + (lookAngle.y * 1.5 - deltaMovement.y) * 1,
// lookAngle.z * 0.1 + (lookAngle.z * 1.5 - deltaMovement.z) * 1
// )
// }
// else {
// setBehaviourFlag(PokemonBehaviourFlag.FLYING, false)
// this.setDeltaMovement(0.0, 0.0, 0.0)
// }
}
fun Entity.isNearGround(): Boolean {
val blockBelow: BlockPos = this.blockPosition().below()
return this.level().getBlockState(blockBelow).isSolid()
}
// override fun jump() {
//// val vec3d = this.velocity
////
////
////
//// this.setVelocity(vec3d.x, this.jumpVelocity.toDouble(), vec3d.z)
//// if (this.isSprinting) {
//// val f = this.yaw * 0.017453292f
//// this.velocity =
//// velocity.add((-MathHelper.sin(f) * 0.2f).toDouble(), 0.0, (MathHelper.cos(f) * 0.2f).toDouble())
//// }
////
//// this.velocityDirty = true
// }
private fun getControlledRotation(controller: LivingEntity): Vec2 {
return this.riding.controlledRotation(this, controller as Player)
}
override fun onPassengerTurned(entityToUpdate: Entity) {
return this.riding.clampPassengerRotation(this, entityToUpdate as? LivingEntity ?: return)
}
override fun positionRider(passenger: Entity, positionUpdater: MoveFunction) {
if (this.hasPassenger(passenger)) {
val index = passengers.indexOf(passenger).takeIf { it >= 0 && it < seats.size } ?: return
val seat = seats[index]
val seatOffset = seat.getOffset(getCurrentPoseType()).toVector3f()
val center = Vector3f(0f, this.bbHeight/2, 0f)
val seatToCenter = center.sub(seatOffset, Vector3f())
val orientation = (passengers.first() as Rollable).orientation ?: Matrix3f().rotate(-(180f + passenger.yRot).toRadians(), Vector3f(0f, 1f, 0f))
val rotatedOffset = orientation.transform(seatToCenter, Vector3f()).add(center).sub(Vector3f(0f, passenger.bbHeight/2, 0f))
positionUpdater.accept(passenger, this.x + rotatedOffset.x, this.y + rotatedOffset.y, this.z + rotatedOffset.z)
if (passenger is LivingEntity) {
this.riding.updatePassengerRotation(this, passenger)
this.riding.clampPassengerRotation(this, passenger)
}
}
}
override fun getControllingPassenger(): LivingEntity? {
val riders = this.passengers.filterIsInstance<LivingEntity>()
if (riders.isEmpty()) {
riding.states.clear()
return null
}
val event = SelectDriverEvent(riders.toSet())
val owner = riders.find { it.uuid == ownerUUID }
if (owner != null) {
event.suggest(owner, 0)
}
CobblemonEvents.SELECT_DRIVER.emit(event)
return event.result()
}
override fun getDismountLocationForPassenger(passenger: LivingEntity): Vec3 {
// val seat = this.riding.seats.firstOrNull { it.occupant() == passenger }
// seat?.dismount()
return super.getDismountLocationForPassenger(passenger)
}
override fun getRiddenInput(controller: Player, movementInput: Vec3): Vec3 {
return this.riding.velocity(this, controller, movementInput)
}
override fun getRiddenSpeed(controller: Player): Float {
return this.riding.speed(this, controller)
}
var jumpInputStrength: Int = 0 // move this
override fun onPlayerJump(strength: Int) {
// See if this controls the hot bar element
var strength = strength
if (strength < 0) {
strength = 0
} else {
// this.jumping = true
// update anger? hunwah
}
this.jumpInputStrength = strength
if (strength >= 90) {
// this.jumpStrength = 1.0f
} else {
// this.jumpStrength = 0.4f + 0.4f * strength.toFloat() / 90.0f
}
}
override fun canJump(): Boolean {
return true
}
override fun handleStartJump(height: Int) {
this.jumping = true
}
fun side() = if (delegate is PokemonServerDelegate) "SERVER" else "CLIENT"
override fun handleStopJump() {
jumping = false
// Set back to land pose type?
}
override fun dismountsUnderwater(): Boolean {
return true
}
override fun getDefaultGravity(): Double {
val regularGravity = super.getDefaultGravity()
if (this.passengers.isEmpty()) {
return regularGravity
}
return riding.gravity(this, regularGravity) ?: regularGravity
}
/**
* A utility method to resolve the [Codec] of [Pokemon] aware if the [world] is client sided or not.
*
@@ -1597,5 +1796,4 @@ open class PokemonEntity(
override fun resolveEntityScan(): LivingEntity {
return this
}
}
}
@@ -196,7 +196,7 @@ class PokemonServerDelegate : PokemonSideDelegate {
}
fun updatePoseType() {
if (!entity.enablePoseTypeRecalculation) {
if (!entity.enablePoseTypeRecalculation || entity.passengers.isNotEmpty()) {
return
}
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.gametest
import com.cobblemon.mod.common.CobblemonEntities
import com.cobblemon.mod.common.api.pokemon.PokemonProperties.Companion.parse
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.core.BlockPos
import net.minecraft.gametest.framework.GameTest
import net.minecraft.gametest.framework.GameTestHelper
class CobblemonGameTests {
@GameTest(template = "")
fun spawnBidoof(context: GameTestHelper) {
context.succeedWhen {
val bidoof = parse("bidoof").create()
bidoof.ivs[Stats.ATTACK] = 31
val target = BlockPos(context.relativePos(BlockPos(0, 0, 0)))
context.assertEntityPresent(CobblemonEntities.POKEMON)
context.assertEntityData(target, CobblemonEntities.POKEMON, PokemonEntity::pokemon, bidoof)
}
}
}
@@ -0,0 +1,34 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.net.messages.client.orientation
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.util.*
import net.minecraft.network.RegistryFriendlyByteBuf
import org.joml.Matrix3f
class S2CUpdateOrientationPacket internal constructor(val entityId: Int, val orientation: Matrix3f?) : NetworkPacket<S2CUpdateOrientationPacket> {
override val id = ID
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeInt(entityId)
buffer.writeBoolean(orientation != null)
if (orientation != null) {
buffer.writeMatrix3f(orientation)
}
}
companion object {
val ID = cobblemonResource("s2c_update_orientation")
fun decode(buffer: RegistryFriendlyByteBuf): S2CUpdateOrientationPacket {
val entityId = buffer.readInt()
val orientation = if (buffer.readBoolean()) buffer.readMatrix3f() else null
return S2CUpdateOrientationPacket(entityId, orientation)
}
}
}
@@ -25,14 +25,14 @@ import net.minecraft.resources.ResourceLocation
* @author Licious
* @since December 29th, 2022
*/
internal class UnvalidatedPlaySoundS2CPacket(
val sound: ResourceLocation,
val category: SoundSource,
val x: Double,
val y: Double,
val z: Double,
val volume: Float,
val pitch: Float
class UnvalidatedPlaySoundS2CPacket(
var sound: ResourceLocation,
var category: SoundSource,
var x: Double,
var y: Double,
var z: Double,
var volume: Float,
var pitch: Float
) : NetworkPacket<UnvalidatedPlaySoundS2CPacket> {
override val id = ID
@@ -18,7 +18,7 @@ import net.minecraft.network.protocol.PacketUtils
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket
import net.minecraft.world.phys.Vec3
abstract class SpawnExtraDataEntityPacket<T: NetworkPacket<T>, E : Entity>(private val vanillaSpawnPacket: ClientboundAddEntityPacket) : NetworkPacket<T> {
abstract class SpawnExtraDataEntityPacket<T: NetworkPacket<T>, E : Entity>(var vanillaSpawnPacket: ClientboundAddEntityPacket) : NetworkPacket<T> {
override fun encode(buffer: RegistryFriendlyByteBuf) {
this.encodeEntityData(buffer)
this.vanillaSpawnPacket.write(buffer)
@@ -30,13 +30,14 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.Entity
class SpawnNPCPacket(
private val npcClass: ResourceLocation,
private val aspects: Set<String>,
private val level: Int,
private val battleIds: Set<UUID>,
private val name: Component,
private val poseType: PoseType,
private val texture: NPCPlayerTexture,
var npcClass: ResourceLocation,
var aspects: Set<String>,
var level: Int,
var battleIds: Set<UUID>,
var name: Component,
var poseType: PoseType,
var texture: NPCPlayerTexture,
var hideNameTag: Boolean,
vanillaSpawnPacket: ClientboundAddEntityPacket
) : SpawnExtraDataEntityPacket<SpawnNPCPacket, NPCEntity>(vanillaSpawnPacket) {
@@ -50,6 +51,7 @@ class SpawnNPCPacket(
entity.name,
entity.entityData.get(NPCEntity.POSE_TYPE),
entity.entityData.get(NPCEntity.NPC_PLAYER_TEXTURE),
entity.hideNameTag,
vanillaSpawnPacket
)
@@ -64,6 +66,7 @@ class SpawnNPCPacket(
if (this.texture.model != NPCPlayerModelType.NONE) {
buffer.writeByteArray(this.texture.texture)
}
buffer.writeBoolean(this.hideNameTag)
}
override fun applyData(entity: NPCEntity) {
@@ -74,6 +77,7 @@ class SpawnNPCPacket(
entity.entityData.set(NPCEntity.ASPECTS, aspects)
entity.entityData.set(NPCEntity.POSE_TYPE, poseType)
entity.entityData.set(NPCEntity.NPC_PLAYER_TEXTURE, texture)
entity.entityData.set(NPCEntity.HIDE_NAME_TAG, this.hideNameTag)
}
override fun checkType(entity: Entity): Boolean = entity is NPCEntity
@@ -93,9 +97,10 @@ class SpawnNPCPacket(
} else {
NPCPlayerTexture(byteArrayOf(), model)
}
val hideNameTag = buffer.readBoolean()
val vanillaPacket = decodeVanillaPacket(buffer)
return SpawnNPCPacket(npc, aspects, level, battleIds, name, poseType, texture, vanillaPacket)
return SpawnNPCPacket(npc, aspects, level, battleIds, name, poseType, texture, hideNameTag, vanillaPacket)
}
}
@@ -24,26 +24,26 @@ import net.minecraft.network.protocol.game.ClientboundAddEntityPacket
import net.minecraft.resources.ResourceLocation
class SpawnPokemonPacket(
private val ownerId: UUID?,
private val scaleModifier: Float,
private val speciesId: ResourceLocation,
private val gender: Gender,
private val shiny: Boolean,
private val formName: String,
private val aspects: Set<String>,
private val battleId: UUID?,
private val phasingTargetId: Int,
private val beamMode: Byte,
private val platform: PlatformType,
private val nickname: MutableComponent?,
private val labelLevel: Int,
private val poseType: PoseType,
private val unbattlable: Boolean,
private val hideLabel: Boolean,
private val caughtBall: ResourceLocation,
private val spawnYaw: Float,
private val friendship: Int,
private val freezeFrame: Float,
var ownerId: UUID?,
var scaleModifier: Float,
var speciesId: ResourceLocation,
var gender: Gender,
var shiny: Boolean,
var formName: String,
var aspects: Set<String>,
var battleId: UUID?,
var phasingTargetId: Int,
var beamMode: Byte,
var platform: PlatformType,
var nickname: MutableComponent?,
var labelLevel: Int,
var poseType: PoseType,
var unbattlable: Boolean,
var hideLabel: Boolean,
var caughtBall: ResourceLocation,
var spawnYaw: Float,
var friendship: Int,
var freezeFrame: Float,
vanillaSpawnPacket: ClientboundAddEntityPacket
) : SpawnExtraDataEntityPacket<SpawnPokemonPacket, PokemonEntity>(vanillaSpawnPacket) {
@@ -26,7 +26,7 @@ import net.minecraft.network.RegistryFriendlyByteBuf
* @author Hiroku
* @since June 20th, 2022
*/
class OpenPCPacket(val storeID: UUID, val box: Int = 1) : NetworkPacket<OpenPCPacket> {
class OpenPCPacket(val storeID: UUID, val box: Int = 0) : NetworkPacket<OpenPCPacket> {
override val id = ID
@@ -24,17 +24,18 @@ import java.util.UUID
* @author Village
* @since January 7th, 2023
*/
class InteractPokemonUIPacket(val pokemonID: UUID, val canMountShoulder: Boolean): NetworkPacket<InteractPokemonUIPacket> {
class InteractPokemonUIPacket(val pokemonID: UUID, val canMountShoulder: Boolean, val canRide: Boolean): NetworkPacket<InteractPokemonUIPacket> {
override val id = ID
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeUUID(pokemonID)
buffer.writeBoolean(canMountShoulder)
buffer.writeBoolean(canRide)
}
companion object {
val ID = cobblemonResource("interact_pokemon_ui")
fun decode(buffer: RegistryFriendlyByteBuf) = InteractPokemonUIPacket(buffer.readUUID(), buffer.readBoolean())
fun decode(buffer: RegistryFriendlyByteBuf) = InteractPokemonUIPacket(buffer.readUUID(), buffer.readBoolean(), buffer.readBoolean())
}
}
@@ -0,0 +1,34 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.net.messages.server.orientation
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.readMatrix3f
import com.cobblemon.mod.common.util.writeMatrix3f
import net.minecraft.network.RegistryFriendlyByteBuf
import org.joml.Matrix3f
class C2SUpdateOrientationPacket internal constructor(val orientation: Matrix3f?) : NetworkPacket<C2SUpdateOrientationPacket> {
override val id = ID
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeBoolean(orientation != null)
if (orientation != null) {
buffer.writeMatrix3f(orientation)
}
}
companion object {
val ID = cobblemonResource("c2s_update_orientation")
fun decode(buffer: RegistryFriendlyByteBuf): C2SUpdateOrientationPacket {
val orientation = if (buffer.readBoolean()) buffer.readMatrix3f() else null
return C2SUpdateOrientationPacket(orientation)
}
}
}
@@ -24,14 +24,15 @@ import java.util.UUID
* @author Village
* @since January 7th, 2023
*/
class InteractPokemonPacket(val pokemonID: UUID, val mountShoulder: Boolean) : NetworkPacket<InteractPokemonPacket> {
class InteractPokemonPacket(val pokemonID: UUID, val mountShoulder: Boolean, val ride: Boolean) : NetworkPacket<InteractPokemonPacket> {
override val id = ID
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeUUID(pokemonID)
buffer.writeBoolean(mountShoulder)
buffer.writeBoolean(ride)
}
companion object {
val ID = cobblemonResource("interact_pokemon")
fun decode(buffer: RegistryFriendlyByteBuf) = InteractPokemonPacket(buffer.readUUID(), buffer.readBoolean())
fun decode(buffer: RegistryFriendlyByteBuf) = InteractPokemonPacket(buffer.readUUID(), buffer.readBoolean(), buffer.readBoolean())
}
}
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.net.serverhandling.evolution
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
import com.cobblemon.mod.common.net.messages.server.pokemon.update.evolution.AcceptEvolutionPacket
import com.cobblemon.mod.common.util.isInBattle
import com.cobblemon.mod.common.util.party
import net.minecraft.server.MinecraftServer
import net.minecraft.server.level.ServerPlayer
@@ -17,7 +18,7 @@ import net.minecraft.server.level.ServerPlayer
object AcceptEvolutionHandler : ServerNetworkPacketHandler<AcceptEvolutionPacket> {
override fun handle(packet: AcceptEvolutionPacket, server: MinecraftServer, player: ServerPlayer) {
val pokemon = player.party()[packet.pokemonUUID] ?: return
if (pokemon.entity?.isBusy == true) return
if (player.isInBattle() || pokemon.entity?.isBusy == true) return
val evolution = pokemon.evolutionProxy.server().firstOrNull { evolution -> evolution.id.equals(packet.evolutionId, true) } ?: return
pokemon.evolutionProxy.server().start(evolution)
}
@@ -0,0 +1,23 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.net.serverhandling.orientation
import com.cobblemon.mod.common.Rollable
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
import com.cobblemon.mod.common.net.messages.server.orientation.C2SUpdateOrientationPacket
import net.minecraft.server.MinecraftServer
import net.minecraft.server.level.ServerPlayer
object OrientationPacketHandler : ServerNetworkPacketHandler<C2SUpdateOrientationPacket> {
override fun handle(packet: C2SUpdateOrientationPacket, server: MinecraftServer, player: ServerPlayer) {
if (player is Rollable) {
player.updateOrientation { _ -> packet.orientation }
}
}
}
@@ -24,9 +24,11 @@ object InteractPokemonHandler : ServerNetworkPacketHandler<InteractPokemonPacket
return
}
pokemonEntity.tryMountingShoulder(player)
} else if (packet.ride) {
player.startRiding(pokemonEntity)
} else {
pokemonEntity.offerHeldItem(player, player.mainHandItem)
}
}
}
}
}
@@ -28,6 +28,7 @@ import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroup
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroups
import com.cobblemon.mod.common.api.pokemon.moves.Learnset
import com.cobblemon.mod.common.api.pokemon.stats.Stat
import com.cobblemon.mod.common.api.riding.RidingProperties
import com.cobblemon.mod.common.api.types.ElementalType
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.entity.PoseType
@@ -96,6 +97,8 @@ class FormData(
private var _height: Float? = null,
@SerializedName("weight")
private var _weight: Float? = null,
@SerializedName("riding")
private var _riding: RidingProperties? = null,
val requiredMove: String? = null,
val requiredItem: String? = null,
/** For forms that can accept different items (e.g. Arceus-Grass: Meadow Plate or Grassium-Z). */
@@ -172,6 +175,8 @@ class FormData(
val eggGroups: Set<EggGroup>
get() = _eggGroups ?: species.eggGroups
val riding: RidingProperties
get() = _riding ?: species.riding
/**
* The height in decimeters
@@ -293,6 +298,7 @@ class FormData(
pb.writeString(ability.template.name)
}
}
buffer.writeNullable(_riding) { pb, riding -> riding.encode(buffer) }
}
override fun decode(buffer: RegistryFriendlyByteBuf) {
@@ -329,6 +335,7 @@ class FormData(
}.forEach { add(Priority.NORMAL, it) }
}
}
this._riding = buffer.readNullable { pb -> RidingProperties.decode(buffer) }
}
/**
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.pokemon
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonBuildDetails
import com.cobblemon.mod.common.CobblemonNetwork.sendPacketToPlayers
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.abilities.Abilities
@@ -58,6 +59,8 @@ import com.cobblemon.mod.common.api.reactive.Observable
import com.cobblemon.mod.common.api.reactive.SettableObservable
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.api.scheduling.afterOnServer
import com.cobblemon.mod.common.api.storage.InvalidSpeciesException
import com.cobblemon.mod.common.api.riding.RidingProperties
import com.cobblemon.mod.common.api.storage.StoreCoordinates
import com.cobblemon.mod.common.api.storage.party.NPCPartyStore
import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore
@@ -539,6 +542,9 @@ open class Pokemon : ShowdownIdentifiable {
*/
internal var heldItem: ItemStack = ItemStack.EMPTY
val riding: RidingProperties
get() = this.form.riding
init {
storeCoordinates.subscribe { if (it != null && it.store !is PCStore && this.tetheringId != null) afterOnServer(seconds = 0.05F) { this.tetheringId = null } }
storeCoordinates.subscribe {
@@ -548,6 +554,7 @@ open class Pokemon : ShowdownIdentifiable {
}
}
open fun getStat(stat: Stat) = Cobblemon.statProvider.getStatForPokemon(this, stat)
/**
@@ -31,6 +31,7 @@ import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroups
import com.cobblemon.mod.common.api.pokemon.moves.Learnset
import com.cobblemon.mod.common.api.pokemon.stats.Stat
import com.cobblemon.mod.common.api.storage.InvalidSpeciesException
import com.cobblemon.mod.common.api.riding.RidingProperties
import com.cobblemon.mod.common.api.types.ElementalType
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.entity.PoseType.Companion.FLYING_POSES
@@ -123,6 +124,9 @@ class Species : ClientDataSynchronizer<Species>, ShowdownIdentifiable {
var forms = mutableListOf<FormData>()
private set
var riding: RidingProperties = RidingProperties()
private set
val standardForm by lazy { FormData(_evolutions = this.evolutions).initialize(this) }
var labels = hashSetOf<String>()
@@ -249,6 +253,8 @@ class Species : ClientDataSynchronizer<Species>, ShowdownIdentifiable {
pb.writeBoolean(ability is CommonAbility)
pb.writeString(ability.template.name)
}
this.riding.encode(buffer)
}
override fun decode(buffer: RegistryFriendlyByteBuf) {
@@ -290,6 +296,7 @@ class Species : ClientDataSynchronizer<Species>, ShowdownIdentifiable {
pool.add(Priority.NORMAL, it)
}
}
this.riding = RidingProperties.decode(buffer)
this.initialize()
}
@@ -124,6 +124,10 @@ object CobblemonHeldItemManager : BaseCobblemonHeldItemManager() {
if (battle.isPvP && !consumeHeldItems) {
return
}
// Block stealing from NPCs
if (battle.isPvN) {
return
}
// if items aren't consumed, then we don't want to give them to wild pokemon (dupe)
if (this.giveItemEffect.contains(effectId) && (pokemon.actor is PlayerBattleActor || consumeHeldItems)) {
this.give(pokemon, itemID)
@@ -0,0 +1,123 @@
/*
* 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.pokemon.riding.controllers
import com.bedrockk.molang.Expression
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.Rollable
import com.cobblemon.mod.common.api.riding.controller.RideController
import com.cobblemon.mod.common.api.riding.controller.posing.PoseOption
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.resolveFloat
import com.cobblemon.mod.common.util.toVec3d
import com.cobblemon.mod.common.util.withQueryValue
import com.cobblemon.mod.common.util.writeString
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
class BirdAirController : RideController {
override val key = KEY
override val poseProvider = PoseProvider(PoseType.HOVER)
.with(PoseOption(PoseType.FLY) { it.deltaMovement.horizontalDistance() > 0.1 })
override val condition: (PokemonEntity) -> Boolean = { true }
var jumpVector = listOf("0".asExpression(), "0.3".asExpression(), "0".asExpression())
private set
var gravity: Expression = "0".asExpression()
private set
var horizontalAcceleration: Expression = "0.1".asExpression()
private set
var verticalAcceleration: Expression = "0.1".asExpression()
private set
var speed: Expression = "1.0".asExpression()
private set
override fun speed(entity: PokemonEntity, driver: Player): Float {
return getRuntime(entity).resolveFloat(speed)
}
override fun rotation(entity: PokemonEntity, driver: LivingEntity): Vec2 {
return Vec2(driver.xRot * 0.5f, driver.yRot)
}
override fun velocity(entity: PokemonEntity, driver: Player, input: Vec3): Vec3 {
val f = driver.xxa * 0.2f
var g = driver.zza
if (g <= 0.0f) {
g *= 0.25f
}
var jumpVector = Vec3.ZERO
if (entity.jumpInputStrength > 0) {
val runtime = getRuntime(entity)
runtime.environment.query.addFunction("jump_strength") { DoubleValue(entity.jumpInputStrength.toDouble()) }
val jumpForces = this.jumpVector.map { runtime.resolveFloat(it) }
jumpVector = Vec3(jumpForces[0].toDouble(), jumpForces[1].toDouble(), jumpForces[2].toDouble())
jumpVector = jumpVector.toVector3f().mul((driver as Rollable).orientation).toVec3d()
entity.jumpInputStrength = 0
entity.addDeltaMovement(jumpVector)
}
val velocity = Vec3(f.toDouble(), 0.0, g.toDouble())
return velocity
}
override fun canJump(
entity: PokemonEntity,
driver: Player
): Boolean {
return true
}
override fun jumpForce(
entity: PokemonEntity,
driver: Player,
jumpStrength: Int
): Vec3 {
return Vec3.ZERO
}
override fun gravity(entity: PokemonEntity, regularGravity: Double): Double? {
return getRuntime(entity)
.withQueryValue("gravity", DoubleValue(regularGravity))
.resolveFloat(gravity)
.toDouble()
}
override fun shouldRoll(entity: PokemonEntity) = true
override fun encode(buffer: RegistryFriendlyByteBuf) {
super.encode(buffer)
buffer.writeString(gravity.toString())
buffer.writeString(horizontalAcceleration.toString())
buffer.writeString(verticalAcceleration.toString())
buffer.writeString(speed.toString())
}
override fun decode(buffer: RegistryFriendlyByteBuf) {
gravity = buffer.readString().asExpression()
horizontalAcceleration = buffer.readString().asExpression()
verticalAcceleration = buffer.readString().asExpression()
speed = buffer.readString().asExpression()
}
companion object {
val KEY = cobblemonResource("air/bird")
}
}
@@ -0,0 +1,152 @@
/*
* 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.pokemon.riding.controllers
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.api.riding.controller.RideController
import com.cobblemon.mod.common.api.riding.controller.posing.PoseOption
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonBehaviourFlag
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.riding.states.CompositeState
import com.cobblemon.mod.common.util.adapters.riding.RideControllerAdapter
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.getString
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.resolveFloat
import com.cobblemon.mod.common.util.writeString
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
class FallToFlightCompositeController : RideController {
override val key = KEY
override val poseProvider = PoseProvider(PoseType.STAND)
.with(PoseOption(PoseType.WALK) { it.entityData.get(PokemonEntity.MOVING) })
override val condition: (PokemonEntity) -> Boolean = { true }
var minimumForwardSpeed: Expression = "0.5".asExpression()
private set
var minimumFallSpeed: Expression = "0.5".asExpression()
private set
var landController: RideController = GenericLandController()
private set
var flightController: RideController = GliderAirController()
private set
override fun pose(entity: PokemonEntity): PoseType {
return getActiveController(entity).poseProvider.select(entity)
}
fun getActiveController(entity: PokemonEntity): RideController {
val state = getState(entity, ::CompositeState)
return state.activeController ?: let {
val controller = if (entity.getCurrentPoseType() in PoseType.FLYING_POSES) {
entity.setBehaviourFlag(PokemonBehaviourFlag.FLYING, true)
flightController
} else {
entity.setBehaviourFlag(PokemonBehaviourFlag.FLYING, false)
landController
}
state.activeController = controller
state.timeTransitioned = entity.level().gameTime
controller
}
}
fun checkShouldBeFlying(entity: PokemonEntity, isFlyingAlready: Boolean): Boolean {
val runtime = getRuntime(entity)
val minFallingSpeed = runtime.resolveFloat(minimumFallSpeed)
val minForwardSpeed = runtime.resolveFloat(minimumForwardSpeed)
val grounded = entity.onGround()
return if (isFlyingAlready) {
!grounded
} else {
entity.deltaMovement.y <= -minFallingSpeed && entity.deltaMovement.horizontalDistance() >= minForwardSpeed
}
}
override fun speed(
entity: PokemonEntity,
driver: Player
): Float {
val state = getState(entity, ::CompositeState)
val shouldBeFlying = checkShouldBeFlying(entity, state.activeController == flightController)
if (state.activeController == flightController && !shouldBeFlying) { // && entity.onGround() && state.timeTransitioned + 20 < entity.level().gameTime) {
state.activeController = landController
entity.setBehaviourFlag(PokemonBehaviourFlag.FLYING, false)
} else if (state.activeController == landController && shouldBeFlying) {
state.activeController = flightController
entity.setBehaviourFlag(PokemonBehaviourFlag.FLYING, true)
}
return getActiveController(entity).speed(entity, driver)
}
override fun rotation(entity: PokemonEntity, driver: LivingEntity): Vec2 {
return getActiveController(entity).rotation(entity, driver)
}
override fun velocity(
entity: PokemonEntity,
driver: Player,
input: Vec3
): Vec3 {
return getActiveController(entity).velocity(entity, driver, input)
}
override fun canJump(entity: PokemonEntity, driver: Player) = true
override fun jumpForce(
entity: PokemonEntity,
driver: Player,
jumpStrength: Int
): Vec3 {
val controller = getActiveController(entity)
return controller.jumpForce(entity, driver, jumpStrength)
}
override fun gravity(entity: PokemonEntity, regularGravity: Double): Double? {
return getActiveController(entity).gravity(entity, regularGravity)
}
override fun shouldRoll(entity: PokemonEntity): Boolean = getActiveController(entity).shouldRoll(entity)
override fun encode(buffer: RegistryFriendlyByteBuf) {
super.encode(buffer)
buffer.writeString(minimumForwardSpeed.getString())
buffer.writeString(minimumFallSpeed.getString())
landController.encode(buffer)
flightController.encode(buffer)
}
override fun decode(buffer: RegistryFriendlyByteBuf) {
minimumForwardSpeed = buffer.readString().asExpression()
minimumFallSpeed = buffer.readString().asExpression()
landController = buffer.readResourceLocation().let { key ->
val controller = RideControllerAdapter.types[key]?.getConstructor()?.newInstance() ?: error("Unknown controller key: $key")
controller.decode(buffer)
controller
}
flightController = buffer.readResourceLocation().let { key ->
val controller = RideControllerAdapter.types[key]?.getConstructor()?.newInstance() ?: error("Unknown controller key: $key")
controller.decode(buffer)
controller
}
}
companion object {
val KEY = cobblemonResource("composite/fall_to_flight")
}
}
@@ -0,0 +1,132 @@
/*
* 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.pokemon.riding.controllers
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.api.riding.controller.RideController
import com.cobblemon.mod.common.api.riding.controller.posing.PoseOption
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.blockPositionsAsListRounded
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.getString
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.resolveFloat
import com.cobblemon.mod.common.util.writeString
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
import net.minecraft.world.phys.shapes.Shapes
class GenericLandController : RideController {
companion object {
val KEY: ResourceLocation = cobblemonResource("land/generic")
}
// private var previousVelocity = Vec3d.ZERO
var canJump = "true".asExpression()
private set
var jumpVector = listOf("0".asExpression(), "0.3".asExpression(), "0".asExpression())
private set
var speed = "1.0".asExpression()
private set
var driveFactor = "1.0".asExpression()
private set
var reverseDriveFactor = "0.25".asExpression()
private set
var strafeFactor = "0.2".asExpression()
private set
@Transient
override val key: ResourceLocation = KEY
@Transient
override val poseProvider: PoseProvider = PoseProvider(PoseType.STAND).with(PoseOption(PoseType.WALK) { it.deltaMovement.horizontalDistance() > 0.1 })
@Transient
override val condition: (PokemonEntity) -> Boolean = { entity ->
// Are there any blocks under the mon that aren't air or fluid
// Cant just check one block since some mons may be more than one block big
// This should be changed so that the any predicate is only ran on blocks under the mon
Shapes.create(entity.boundingBox).blockPositionsAsListRounded().any {
//Need to check other fluids
if (entity.isInWater || entity.isUnderWater) {
return@any false
}
//This might not actually work, depending on what the yPos actually is. yPos of the middle of the entity? the feet?
if (it.y.toDouble() == (entity.position().y)) {
val blockState = entity.level().getBlockState(it.below())
return@any !blockState.isAir && blockState.fluidState.isEmpty
}
true
}
}
override fun speed(entity: PokemonEntity, driver: Player): Float {
return getRuntime(entity).resolveFloat(speed)
}
override fun rotation(entity: PokemonEntity, driver: LivingEntity): Vec2 {
return Vec2(driver.xRot * 0.5f, driver.yRot)
}
override fun velocity(entity: PokemonEntity, driver: Player, input: Vec3): Vec3 {
val runtime = getRuntime(entity)
val driveFactor = runtime.resolveFloat(this.driveFactor)
val strafeFactor = runtime.resolveFloat(this.strafeFactor)
val f = driver.xxa * strafeFactor
var g = driver.zza * driveFactor
if (g <= 0.0f) {
g *= runtime.resolveFloat(this.reverseDriveFactor)
}
val velocity = Vec3(f.toDouble(), 0.0, g.toDouble())
return velocity
}
override fun canJump(entity: PokemonEntity, driver: Player) = getRuntime(entity).resolveBoolean(canJump)
override fun jumpForce(entity: PokemonEntity, driver: Player, jumpStrength: Int): Vec3 {
val runtime = getRuntime(entity)
runtime.environment.query.addFunction("jump_strength") { DoubleValue(jumpStrength.toDouble()) }
val jumpVector = jumpVector.map { runtime.resolveFloat(it) }
return Vec3(jumpVector[0].toDouble(), jumpVector[1].toDouble(), jumpVector[2].toDouble())
}
override fun encode(buffer: RegistryFriendlyByteBuf) {
super.encode(buffer)
buffer.writeString(this.speed.getString())
buffer.writeString(this.canJump.getString())
buffer.writeString(this.jumpVector[0].getString())
buffer.writeString(this.jumpVector[1].getString())
buffer.writeString(this.jumpVector[2].getString())
buffer.writeString(this.driveFactor.getString())
buffer.writeString(this.reverseDriveFactor.getString())
buffer.writeString(this.strafeFactor.getString())
}
override fun decode(buffer: RegistryFriendlyByteBuf) {
this.speed = buffer.readString().asExpression()
this.canJump = buffer.readString().asExpression()
this.jumpVector = listOf(
buffer.readString().asExpression(),
buffer.readString().asExpression(),
buffer.readString().asExpression()
)
this.driveFactor = buffer.readString().asExpression()
this.reverseDriveFactor = buffer.readString().asExpression()
this.strafeFactor = buffer.readString().asExpression()
}
}
@@ -0,0 +1,123 @@
/*
* 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.pokemon.riding.controllers
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.api.riding.controller.RideController
import com.cobblemon.mod.common.api.riding.controller.posing.PoseOption
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.blockPositionsAsListRounded
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.getString
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.resolveFloat
import com.cobblemon.mod.common.util.writeString
import kotlin.math.max
import kotlin.math.min
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
import net.minecraft.world.phys.shapes.Shapes
class GenericLiquidController : RideController {
companion object {
val KEY: ResourceLocation = cobblemonResource("swim/generic")
}
var canJump = "true".asExpression()
private set
var jumpVector = listOf("0".asExpression(), "0.3".asExpression(), "0".asExpression())
private set
var speed = "1.0".asExpression()
private set
var driveFactor = "1.0".asExpression()
private set
var reverseDriveFactor = "0.25".asExpression()
private set
var strafeFactor = "0.2".asExpression()
private set
override val key: ResourceLocation = KEY
override val poseProvider: PoseProvider = PoseProvider(PoseType.FLOAT)
.with(PoseOption(PoseType.SWIM) { it.isSwimming && it.entityData.get(PokemonEntity.MOVING) })
override val condition: (PokemonEntity) -> Boolean = { entity ->
//This could be kinda weird... what if the top of the mon is in a fluid but the bottom isnt?
Shapes.create(entity.boundingBox).blockPositionsAsListRounded().any {
if (entity.isInWater || entity.isUnderWater) {
return@any true
}
val blockState = entity.level().getBlockState(it)
return@any !blockState.fluidState.isEmpty
}
}
override fun speed(entity: PokemonEntity, driver: Player): Float {
return getRuntime(entity).resolveFloat(speed)
}
override fun rotation(entity: PokemonEntity, driver: LivingEntity): Vec2 {
return Vec2(driver.xRot * 0.5f, driver.yRot)
}
override fun velocity(entity: PokemonEntity, driver: Player, input: Vec3): Vec3 {
val runtime = getRuntime(entity)
val driveFactor = runtime.resolveFloat(this.driveFactor)
val strafeFactor = runtime.resolveFloat(this.strafeFactor)
val f = driver.xxa * strafeFactor
var g = driver.zza * driveFactor
if (g <= 0.0f) {
g *= runtime.resolveFloat(this.reverseDriveFactor)
}
val velocity = Vec3(f.toDouble(), 0.0, g.toDouble())
return velocity
}
override fun canJump(entity: PokemonEntity, driver: Player) = getRuntime(entity).resolveBoolean(canJump)
override fun jumpForce(entity: PokemonEntity, driver: Player, jumpStrength: Int): Vec3 {
val runtime = getRuntime(entity)
runtime.environment.query.addFunction("jump_strength") { DoubleValue(jumpStrength.toDouble()) }
val jumpVector = jumpVector.map { runtime.resolveFloat(it) }
return Vec3(jumpVector[0].toDouble(), jumpVector[1].toDouble(), jumpVector[2].toDouble())
}
override fun encode(buffer: RegistryFriendlyByteBuf) {
super.encode(buffer)
buffer.writeString(this.speed.getString())
buffer.writeString(this.canJump.getString())
buffer.writeString(this.jumpVector[0].getString())
buffer.writeString(this.jumpVector[1].getString())
buffer.writeString(this.jumpVector[2].getString())
buffer.writeString(this.driveFactor.getString())
buffer.writeString(this.reverseDriveFactor.getString())
buffer.writeString(this.strafeFactor.getString())
}
override fun decode(buffer: RegistryFriendlyByteBuf) {
this.speed = buffer.readString().asExpression()
this.canJump = buffer.readString().asExpression()
this.jumpVector = listOf(
buffer.readString().asExpression(),
buffer.readString().asExpression(),
buffer.readString().asExpression()
)
this.driveFactor = buffer.readString().asExpression()
this.reverseDriveFactor = buffer.readString().asExpression()
this.strafeFactor = buffer.readString().asExpression()
}
}
@@ -0,0 +1,84 @@
/*
* 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.pokemon.riding.controllers
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.api.riding.controller.RideController
import com.cobblemon.mod.common.api.riding.controller.posing.PoseOption
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.getString
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.resolveDouble
import com.cobblemon.mod.common.util.resolveFloat
import com.cobblemon.mod.common.util.writeString
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
class GliderAirController : RideController {
override val key = KEY
override val poseProvider = PoseProvider(PoseType.HOVER)
.with(PoseOption(PoseType.FLY) { it.deltaMovement.horizontalDistance() > 0.1 })
override val condition: (PokemonEntity) -> Boolean = { true }
var glideSpeed: Expression = "0.1".asExpression()
private set
var speed: Expression = "1.0".asExpression()
private set
var canStrafe: Expression = "false".asExpression()
private set
override fun speed(entity: PokemonEntity, driver: Player): Float {
return getRuntime(entity).resolveFloat(speed)
}
override fun rotation(entity: PokemonEntity, driver: LivingEntity): Vec2 {
return Vec2(driver.xRot, driver.yRot)
}
override fun velocity(entity: PokemonEntity, driver: Player, input: Vec3): Vec3 {
val xVector = if (getRuntime(entity).resolveBoolean(canStrafe)) driver.xxa.toDouble() else 0.0
val yVector = -getRuntime(entity).resolveDouble(glideSpeed)
val zVector = driver.zza.toDouble()
return Vec3(xVector, yVector, zVector)
}
override fun gravity(entity: PokemonEntity, regularGravity: Double): Double? {
return 0.0
}
override fun canJump(entity: PokemonEntity, driver: Player): Boolean {
return false
}
override fun jumpForce(entity: PokemonEntity, driver: Player, jumpStrength: Int) = Vec3.ZERO
override fun encode(buffer: RegistryFriendlyByteBuf) {
super.encode(buffer)
buffer.writeString(glideSpeed.toString())
buffer.writeString(speed.toString())
}
override fun decode(buffer: RegistryFriendlyByteBuf) {
glideSpeed = buffer.readString().asExpression()
speed = buffer.readString().asExpression()
}
companion object {
val KEY: ResourceLocation = cobblemonResource("air/glider")
}
}
@@ -0,0 +1,114 @@
/*
* 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.pokemon.riding.controllers
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.api.riding.controller.RideController
import com.cobblemon.mod.common.api.riding.controller.posing.PoseOption
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.resolveDouble
import com.cobblemon.mod.common.util.resolveFloat
import com.cobblemon.mod.common.util.writeString
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
/**
* Allows for flight like a bird controller, except you don't have to do any "flapping" motion,
* you can just go up and down like creative
*
* @author Apion
* @since January 1, 2025
*/
class HelicopterAirController : RideController {
override val key = KEY
override val poseProvider = PoseProvider(PoseType.HOVER)
.with(PoseOption(PoseType.FLY) { it.deltaMovement.horizontalDistance() > 0.1 })
override val condition: (PokemonEntity) -> Boolean = { true }
var gravity: Expression = "1.0".asExpression()
private set
var horizontalAcceleration: Expression = "0.1".asExpression()
private set
var verticalVelocity: Expression = "1.0".asExpression()
private set
var speed: Expression = "1.0".asExpression()
private set
override fun speed(entity: PokemonEntity, driver: Player): Float {
return getRuntime(entity).resolveFloat(speed)
}
override fun rotation(entity: PokemonEntity, driver: LivingEntity): Vec2 {
return Vec2(driver.xRot * 0.5f, driver.yRot)
}
override fun velocity(entity: PokemonEntity, driver: Player, input: Vec3): Vec3 {
val runtime = getRuntime(entity)
val f = driver.xxa * 0.2f
var g = driver.zza
if (g <= 0.0f) {
g *= 0.25f
}
val yVel = if (driver.jumping) runtime.resolveDouble(verticalVelocity)
else if (driver.isShiftKeyDown) -runtime.resolveDouble(verticalVelocity)
else (entity.gravity)
val velocity = Vec3(f.toDouble(), yVel, g.toDouble())
return velocity
}
override fun canJump(
entity: PokemonEntity,
driver: Player
): Boolean {
return false
}
override fun jumpForce(
entity: PokemonEntity,
driver: Player,
jumpStrength: Int
): Vec3 {
return Vec3.ZERO
}
override fun gravity(entity: PokemonEntity, regularGravity: Double): Double? {
return 0.0
}
override fun encode(buffer: RegistryFriendlyByteBuf) {
super.encode(buffer)
buffer.writeString(gravity.toString())
buffer.writeString(horizontalAcceleration.toString())
buffer.writeString(verticalVelocity.toString())
buffer.writeString(speed.toString())
}
override fun decode(buffer: RegistryFriendlyByteBuf) {
gravity = buffer.readString().asExpression()
horizontalAcceleration = buffer.readString().asExpression()
verticalVelocity = buffer.readString().asExpression()
speed = buffer.readString().asExpression()
}
companion object {
val KEY = cobblemonResource("air/helicopter")
}
}
@@ -0,0 +1,143 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.pokemon.riding.controllers
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.api.riding.controller.RideController
import com.cobblemon.mod.common.api.riding.controller.posing.PoseOption
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonBehaviourFlag
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.riding.states.CompositeState
import com.cobblemon.mod.common.util.adapters.riding.RideControllerAdapter
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.getString
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.resolveInt
import com.cobblemon.mod.common.util.writeString
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
class RunUpToFlightCompositeController : RideController {
override val key = KEY
override val poseProvider = PoseProvider(PoseType.STAND)
.with(PoseOption(PoseType.WALK) { it.entityData.get(PokemonEntity.MOVING) })
override val condition: (PokemonEntity) -> Boolean = { true }
var minimumSpeed: Expression = "0.5".asExpression()
private set
var minimumJump: Expression = "0.5".asExpression()
private set
var landController: RideController = GenericLandController()
private set
var flightController: RideController = BirdAirController()
private set
override fun pose(entity: PokemonEntity): PoseType {
return getActiveController(entity).poseProvider.select(entity)
}
fun getActiveController(entity: PokemonEntity): RideController {
val state = getState(entity, ::CompositeState)
return state.activeController ?: let {
val controller = if (entity.getCurrentPoseType() in PoseType.FLYING_POSES) {
entity.setBehaviourFlag(PokemonBehaviourFlag.FLYING, true)
flightController
} else {
entity.setBehaviourFlag(PokemonBehaviourFlag.FLYING, false)
landController
}
state.activeController = controller
state.timeTransitioned = entity.level().gameTime
controller
}
}
override fun speed(
entity: PokemonEntity,
driver: Player
): Float {
val state = getState(entity, ::CompositeState)
if (state.activeController == flightController && entity.onGround() && state.timeTransitioned + 20 < entity.level().gameTime) {
getState(entity, ::CompositeState).activeController = landController
entity.setBehaviourFlag(PokemonBehaviourFlag.FLYING, false)
}
return getActiveController(entity).speed(entity, driver)
}
override fun rotation(entity: PokemonEntity, driver: LivingEntity): Vec2 {
return getActiveController(entity).rotation(entity, driver)
}
override fun velocity(
entity: PokemonEntity,
driver: Player,
input: Vec3
): Vec3 {
return getActiveController(entity).velocity(entity, driver, input)
}
override fun canJump(entity: PokemonEntity, driver: Player) = true
override fun jumpForce(
entity: PokemonEntity,
driver: Player,
jumpStrength: Int
): Vec3 {
val controller = getActiveController(entity)
if (controller == landController && jumpStrength >= getRuntime(entity).resolveInt(minimumJump)) {
getState(entity, ::CompositeState).let {
it.activeController = flightController
entity.setBehaviourFlag(PokemonBehaviourFlag.FLYING, true)
it.timeTransitioned = entity.level().gameTime
}
}
return controller.jumpForce(entity, driver, jumpStrength)
}
override fun gravity(entity: PokemonEntity, regularGravity: Double): Double? {
return getActiveController(entity).gravity(entity, regularGravity)
}
override fun shouldRoll(entity: PokemonEntity): Boolean = getActiveController(entity).shouldRoll(entity)
override fun encode(buffer: RegistryFriendlyByteBuf) {
super.encode(buffer)
buffer.writeString(minimumSpeed.getString())
buffer.writeString(minimumJump.getString())
landController.encode(buffer)
flightController.encode(buffer)
}
override fun decode(buffer: RegistryFriendlyByteBuf) {
minimumSpeed = buffer.readString().asExpression()
minimumJump = buffer.readString().asExpression()
landController = buffer.readResourceLocation().let { key ->
val controller = RideControllerAdapter.types[key]?.getConstructor()?.newInstance() ?: error("Unknown controller key: $key")
controller.decode(buffer)
controller
}
flightController = buffer.readResourceLocation().let { key ->
val controller = RideControllerAdapter.types[key]?.getConstructor()?.newInstance() ?: error("Unknown controller key: $key")
controller.decode(buffer)
controller
}
}
companion object {
val KEY = cobblemonResource("composite/run_up_to_flight")
}
}
@@ -0,0 +1,94 @@
/*
* 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.pokemon.riding.controllers
import com.cobblemon.mod.common.api.riding.controller.RideController
import com.cobblemon.mod.common.api.riding.controller.posing.PoseOption
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.blockPositionsAsListRounded
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
import net.minecraft.world.phys.shapes.Shapes
class SwimDashController : RideController {
companion object {
val KEY: ResourceLocation = cobblemonResource("swim/dash")
const val DASH_TICKS: Int = 60
}
var dashSpeed = 1F
private set
override val key: ResourceLocation = KEY
override val poseProvider: PoseProvider = PoseProvider(PoseType.FLOAT).with(PoseOption(PoseType.SWIM) { it.isSwimming && it.entityData.get(PokemonEntity.MOVING) })
override val condition: (PokemonEntity) -> Boolean = { entity ->
//This could be kinda weird... what if the top of the mon is in a fluid but the bottom isnt?
Shapes.create(entity.boundingBox).blockPositionsAsListRounded().any {
if (entity.isInWater || entity.isUnderWater) {
return@any true
}
val blockState = entity.level().getBlockState(it)
return@any !blockState.fluidState.isEmpty
}
}
/** Indicates that we are currently enacting a dash, and that further movement inputs should be ignored */
private var dashing = false
private var ticks = 0
override fun speed(entity: PokemonEntity, driver: Player): Float {
if(this.dashing) {
if(this.ticks++ >= DASH_TICKS) {
this.dashing = false
}
return 0.0F
}
this.dashing = true
return this.dashSpeed
}
override fun rotation(entity: PokemonEntity, driver: LivingEntity): Vec2 {
return Vec2(driver.xRot * 0.5f, driver.yRot)
}
override fun velocity(entity: PokemonEntity, driver: Player, input: Vec3): Vec3 {
val f = driver.xxa * 0.05f
var g = driver.zza * 0.6f
if (g <= 0.0f) {
g *= 0.25f
}
return Vec3(f.toDouble(), 0.0, g.toDouble())
}
override fun canJump(entity: PokemonEntity, driver: Player): Boolean {
TODO("Not yet implemented")
}
override fun jumpForce(entity: PokemonEntity, driver: Player, jumpStrength: Int): Vec3 {
TODO("Not yet implemented")
}
override fun encode(buffer: RegistryFriendlyByteBuf) {
super.encode(buffer)
buffer.writeFloat(this.dashSpeed)
}
override fun decode(buffer: RegistryFriendlyByteBuf) {
this.dashSpeed = buffer.readFloat()
}
}
@@ -0,0 +1,158 @@
/*
* 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.pokemon.riding.controllers
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.api.riding.controller.RideController
import com.cobblemon.mod.common.api.riding.controller.posing.PoseOption
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.blockPositionsAsListRounded
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.getString
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.resolveFloat
import com.cobblemon.mod.common.util.writeString
import kotlin.math.absoluteValue
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.util.Mth
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
import net.minecraft.world.phys.shapes.Shapes
class VehicleLandController : RideController {
companion object {
val KEY: ResourceLocation = cobblemonResource("land/vehicle")
}
var canJump = "true".asExpression()
private set
var jumpVector = listOf("0".asExpression(), "0.3".asExpression(), "0".asExpression())
private set
var speed = "0.3".asExpression()
private set
var driveFactor = "1.0".asExpression()
private set
var reverseDriveFactor = "0.25".asExpression()
private set
var minimumSpeedToTurn = "0.1".asExpression()
private set
var rotationSpeed = "45/20".asExpression()
private set
var lookYawLimit = "101".asExpression()
private set
@Transient
override val key: ResourceLocation = KEY
@Transient
override val poseProvider: PoseProvider = PoseProvider(PoseType.STAND).with(PoseOption(PoseType.WALK) { it.deltaMovement.horizontalDistance() > 0.1 })
@Transient
override val condition: (PokemonEntity) -> Boolean = { entity ->
// Are there any blocks under the mon that aren't air or fluid
// Cant just check one block since some mons may be more than one block big
// This should be changed so that the any predicate is only ran on blocks under the mon
Shapes.create(entity.boundingBox).blockPositionsAsListRounded().any {
//Need to check other fluids
if (entity.isInWater || entity.isUnderWater) {
return@any false
}
//This might not actually work, depending on what the yPos actually is. yPos of the middle of the entity? the feet?
if (it.y.toDouble() == (entity.position().y)) {
val blockState = entity.level().getBlockState(it.below())
return@any !blockState.isAir && blockState.fluidState.isEmpty
}
true
}
}
override fun speed(entity: PokemonEntity, driver: Player): Float {
return getRuntime(entity).resolveFloat(speed)
}
override fun rotation(entity: PokemonEntity, driver: LivingEntity): Vec2 {
val rotationDegrees = driver.xxa * getRuntime(entity).resolveFloat(this.rotationSpeed)
return Vec2(driver.xRot, entity.yRot - rotationDegrees)
}
override fun velocity(entity: PokemonEntity, driver: Player, input: Vec3): Vec3 {
val runtime = getRuntime(entity)
val driveFactor = runtime.resolveFloat(this.driveFactor)
var g = driver.zza * driveFactor
if (g <= 0.0f) {
g *= runtime.resolveFloat(this.reverseDriveFactor)
}
if (driver.xxa != 0F && g.absoluteValue < runtime.resolveFloat(this.minimumSpeedToTurn)) {
driver.xxa = 0F
}
val velocity = Vec3(0.0 /* Maybe do drifting here later */, 0.0, g.toDouble())
return velocity
}
override fun updatePassengerRotation(entity: PokemonEntity, driver: LivingEntity) {
driver.yRot += (entity.riding.deltaRotation.y)
driver.setYHeadRot(driver.yHeadRot + (entity.riding.deltaRotation.y))
}
override fun clampPassengerRotation(entity: PokemonEntity, driver: LivingEntity) {
val f = Mth.wrapDegrees(driver.yRot - entity.yRot)
val runtime = getRuntime(entity)
val lookYawLimit = runtime.resolveFloat(this.lookYawLimit)
val g = Mth.clamp(f, -lookYawLimit, lookYawLimit)
driver.yRotO += g - f
driver.yRot = driver.yRot + g - f
driver.setYHeadRot(driver.yRot)
}
override fun canJump(entity: PokemonEntity, driver: Player) = getRuntime(entity).resolveBoolean(canJump)
override fun jumpForce(entity: PokemonEntity, driver: Player, jumpStrength: Int): Vec3 {
val runtime = getRuntime(entity)
runtime.environment.query.addFunction("jump_strength") { DoubleValue(jumpStrength.toDouble()) }
val jumpVector = jumpVector.map { runtime.resolveFloat(it) }
return Vec3(jumpVector[0].toDouble(), jumpVector[1].toDouble(), jumpVector[2].toDouble())
}
override fun encode(buffer: RegistryFriendlyByteBuf) {
super.encode(buffer)
buffer.writeString(this.speed.getString())
buffer.writeString(this.canJump.getString())
buffer.writeString(this.jumpVector[0].getString())
buffer.writeString(this.jumpVector[1].getString())
buffer.writeString(this.jumpVector[2].getString())
buffer.writeString(this.driveFactor.getString())
buffer.writeString(this.reverseDriveFactor.getString())
buffer.writeString(this.minimumSpeedToTurn.getString())
buffer.writeString(this.rotationSpeed.getString())
buffer.writeString(this.lookYawLimit.getString())
}
override fun decode(buffer: RegistryFriendlyByteBuf) {
this.speed = buffer.readString().asExpression()
this.canJump = buffer.readString().asExpression()
this.jumpVector = listOf(
buffer.readString().asExpression(),
buffer.readString().asExpression(),
buffer.readString().asExpression()
)
this.driveFactor = buffer.readString().asExpression()
this.reverseDriveFactor = buffer.readString().asExpression()
this.minimumSpeedToTurn = buffer.readString().asExpression()
this.rotationSpeed = buffer.readString().asExpression()
this.lookYawLimit = buffer.readString().asExpression()
}
}
@@ -0,0 +1,18 @@
/*
* 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.pokemon.riding.states
import com.cobblemon.mod.common.api.riding.RidingState
import com.cobblemon.mod.common.api.riding.controller.RideController
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
open class CompositeState(pokemonEntity: PokemonEntity) : RidingState {
var activeController: RideController? = null
var timeTransitioned = -100L
}
@@ -30,6 +30,7 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.util.Mth
import net.minecraft.world.entity.EntityDimensions
import net.minecraft.world.item.ItemStack
import org.joml.Matrix3f
import java.io.IOException
import java.util.*
@@ -234,4 +235,22 @@ fun ByteBuf.readBitSet(size: Int): BitSet {
return BitSet.valueOf(bs)
}
//fun
fun ByteBuf.writeMatrix3f(matrix: Matrix3f) {
this.writeFloat(matrix.m00)
this.writeFloat(matrix.m01)
this.writeFloat(matrix.m02)
this.writeFloat(matrix.m10)
this.writeFloat(matrix.m11)
this.writeFloat(matrix.m12)
this.writeFloat(matrix.m20)
this.writeFloat(matrix.m21)
this.writeFloat(matrix.m22)
}
fun ByteBuf.readMatrix3f(): Matrix3f {
return Matrix3f(
readFloat(), readFloat(), readFloat(),
readFloat(), readFloat(), readFloat(),
readFloat(), readFloat(), readFloat(),
)
}
@@ -225,6 +225,7 @@ object DataKeys {
const val NPC_HITBOX_WIDTH = "Width"
const val NPC_HITBOX_HEIGHT = "Height"
const val NPC_HITBOX_FIXED = "Fixed"
const val NPC_HIDE_NAME_TAG = "HideNPCNameTag"
// PokemonProperties
const val ELEMENTAL_TYPE = "ElementalType"
@@ -18,6 +18,8 @@ import net.minecraft.client.gui.screens.Screen
import java.util.UUID
import java.util.concurrent.CompletableFuture
import java.util.function.Consumer
import kotlin.math.ceil
import kotlin.math.floor
import kotlin.math.min
import kotlin.random.Random
import net.minecraft.client.resources.model.ModelResourceLocation
@@ -85,6 +87,21 @@ fun isUuid(string: String) : Boolean {
return Regex("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\$").matches(string)
}
fun VoxelShape.blockPositionsAsListRounded(): List<BlockPos> {
val result = mutableListOf<BlockPos>()
forAllBoxes { minX, minY, minZ, maxX, maxY, maxZ ->
for (x in floor(minX).toInt() until ceil(maxX).toInt()) {
for (y in floor(minY).toInt() until ceil(maxY).toInt()) {
for (z in floor(minZ).toInt() until ceil(maxZ).toInt()) {
result.add(BlockPos(x, y, z))
}
}
}
}
return result
}
fun VoxelShape.blockPositionsAsList(): List<BlockPos> {
val result = mutableListOf<BlockPos>()
forAllBoxes { minX, minY, minZ, maxX, maxY, maxZ ->
@@ -36,6 +36,7 @@ import net.minecraft.util.Mth
import net.minecraft.world.InteractionHand
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.item.ItemEntity
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
@@ -46,7 +47,10 @@ import net.minecraft.world.phys.BlockHitResult
import net.minecraft.world.phys.Vec3
import net.minecraft.world.phys.HitResult
import java.util.*
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.min
import kotlin.math.sin
// Stuff like getting their party
fun ServerPlayer.party() = Cobblemon.storage.getParty(this)
@@ -396,7 +400,7 @@ fun Player.giveOrDropItemStack(stack: ItemStack, playSound: Boolean = true) {
val inserted = this.inventory.add(stack)
if (inserted && stack.isEmpty) {
stack.count = 1
this.drop(stack, false)?.makeFakeItem()
this.dropFakeItem(stack)
if (playSound) {
this.level().playSound(null, this.x, this.y, this.z, SoundEvents.ITEM_PICKUP, SoundSource.PLAYERS, 0.2f, ((this.random.nextFloat() - this.random.nextFloat()) * 0.7f + 1.0f) * 2.0f)
}
@@ -410,6 +414,31 @@ fun Player.giveOrDropItemStack(stack: ItemStack, playSound: Boolean = true) {
}
}
/**
* Utility function to mimic the [Player.drop] method but as a fake item entity.
* Avoids cases where other mods listen to that drop method and expect a real item to be dropped.
*/
fun Player.dropFakeItem(stack: ItemStack): ItemEntity {
val d = this.eyeY - 0.3
val itemEntity = ItemEntity(this.level(), this.x, d, this.z, stack)
val f = 0.3F
val g = sin(this.xRot * (PI / 180.0)).toFloat()
val h = cos(this.xRot * (PI / 180.0)).toFloat()
val i = sin(this.yRot * (PI / 180.0)).toFloat()
val j = cos(this.yRot * (PI / 180.0)).toFloat()
val k = this.random.nextFloat() * (PI * 2)
val l = 0.02F * this.random.nextFloat()
itemEntity.deltaMovement = Vec3(
(-i * h * f).toDouble() + cos(k) * l.toDouble(),
(-g * f + 0.1f + (this.random.nextFloat() - this.random.nextFloat()) * 0.1f).toDouble(),
(j * h * f).toDouble() + sin(k) * l.toDouble()
)
itemEntity.makeFakeItem()
return itemEntity
}
/** Retrieves the battle theme associated with this player, or the default PVP theme if null. */
fun ServerPlayer.getBattleTheme() = Cobblemon.playerDataManager.getGenericData(this).battleTheme?.let { BuiltInRegistries.SOUND_EVENT.get(it) } ?: CobblemonSounds.PVP_BATTLE
@@ -423,4 +452,4 @@ fun Player.isPartyBusy() =
fun Player.isUsingPokedex() = isUsingItem &&
((mainHandItem.item is PokedexItem && usedItemHand == InteractionHand.MAIN_HAND) ||
(offhandItem.item is PokedexItem && usedItemHand == InteractionHand.OFF_HAND))
(offhandItem.item is PokedexItem && usedItemHand == InteractionHand.OFF_HAND))
@@ -83,6 +83,7 @@ object NPCClassAdapter : JsonDeserializer<NPCClass> {
obj.get("isInvulnerable")?.let { npcClass.isInvulnerable = it.asBoolean }
obj.get("isLeashable")?.let { npcClass.isLeashable = it.asBoolean }
obj.get("allowProjectileHits")?.let { npcClass.allowProjectileHits = it.asBoolean }
obj.get("hideNameTag")?.let { npcClass.hideNameTag = it.asBoolean }
return npcClass
}
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.util.adapters.riding
import com.cobblemon.mod.common.api.riding.controller.RideController
import com.cobblemon.mod.common.pokemon.riding.controllers.*
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import net.minecraft.resources.ResourceLocation
import java.lang.reflect.Type
/**
* Adapter for deserializing [RideController] types.
*
* @author Hiroku
* @since April 30th, 2024
*/
object RideControllerAdapter : JsonDeserializer<RideController> {
val types: MutableMap<ResourceLocation, Class<out RideController>> = mutableMapOf(
GenericLandController.KEY to GenericLandController::class.java,
GenericLiquidController.KEY to GenericLiquidController::class.java,
SwimDashController.KEY to SwimDashController::class.java,
RunUpToFlightCompositeController.KEY to RunUpToFlightCompositeController::class.java,
BirdAirController.KEY to BirdAirController::class.java,
HelicopterAirController.KEY to HelicopterAirController::class.java,
GliderAirController.KEY to GliderAirController::class.java,
FallToFlightCompositeController.KEY to FallToFlightCompositeController::class.java,
VehicleLandController.KEY to VehicleLandController::class.java
)
override fun deserialize(element: JsonElement, type: Type, context: JsonDeserializationContext): RideController {
val root = element.asJsonObject
val key = root.get("key").asString
val controllerType = types[key.asIdentifierDefaultingNamespace()] ?: throw IllegalArgumentException("Unknown controller: $key")
return context.deserialize(element, controllerType)
}
}
@@ -206,7 +206,7 @@
},
"animation.exeggutor_alolan.ground_walk": {
"loop": true,
"animation_length": 4.79167,
"animation_length": 4.7917,
"bones": {
"leg_left": {
"rotation": {
@@ -817,25 +817,30 @@
"bones": {
"leg_left": {
"rotation": {
"0.0": ["-15+math.clamp(-math.sin(q.anim_time*90*2.5+225)*65,-90,0)", -35, 0],
"0.0": [-15, -35, 0],
"0.5833": [-15, -35, 0],
"0.625": ["-15+math.clamp(-math.sin(q.anim_time*90*2.5+225)*35,-90,0)", -35, 0],
"1.125": ["-15+math.clamp(-math.sin(q.anim_time*90*2.5+225)*35,-90,0)", -35, 0],
"0.7917": [-65, -35, 0],
"0.9583": {
"pre": [-75, -35, 0],
"post": [-75, -35, 0],
"lerp_mode": "catmullrom"
},
"1.125": {
"post": [-65, -35, 0],
"lerp_mode": "catmullrom"
},
"1.2917": [-15, -35, 0],
"1.5833": [-15, -35, 0]
},
"position": {
"0.0": [
"math.clamp(math.sin(q.anim_time*90*2.5+225)*0.5,0,90)",
"math.clamp(math.sin(q.anim_time*90*2.5+225)*3.5,0,90)",
"math.clamp(-math.sin(q.anim_time*90*2.5+225)*2,-90,0)"
],
"0.0": [0, 0, 0],
"0.5833": [0, 0, 0],
"0.625": [
"math.clamp(math.sin(q.anim_time*90*2.5+225)*0.5,0,90)",
"math.clamp(math.sin(q.anim_time*90*2.5+225)*3.5,0,90)",
"math.clamp(-math.sin(q.anim_time*90*2.5+225)*2,-90,0)"
],
"0.625": [0.06, 0.42, -0.24],
"0.7083": [0.18, 1.26, -0.72],
"0.7917": [0.15, 1.08, -0.62],
"0.9167": [0.11, 0.81, -0.47],
"1.0417": [0.07, 0.54, -0.31],
"1.1667": [0.04, 0.27, -0.16],
"1.2917": [0, 0, 0],
"1.5833": [0, 0, 0]
}
@@ -858,25 +863,31 @@
},
"leg_right": {
"rotation": {
"0.0": ["-15+math.clamp(math.sin(q.anim_time*90*2.5+225)*35,-90,0)", 35, 0],
"0.3333": ["-15+math.clamp(math.sin(q.anim_time*90*2.5+225)*35,-90,0)", 35, 0],
"0.0": [-65, 35, 0],
"0.1667": {
"pre": [-75, 35, 0],
"post": [-75, 35, 0],
"lerp_mode": "catmullrom"
},
"0.3333": {
"post": [-65, 35, 0],
"lerp_mode": "catmullrom"
},
"0.5": [-15, 35, 0],
"1.3333": [-15, 35, 0],
"1.375": ["-15+math.clamp(math.sin(q.anim_time*90*2.5+225)*35,-90,0)", 35, 0]
"1.375": [-15, 35, 0],
"1.5833": [-65, 35, 0]
},
"position": {
"0.0": [
"math.clamp(math.sin(q.anim_time*90*2.5+225)*0.5,-90,0)",
"math.clamp(-math.sin(q.anim_time*90*2.5+225)*3.5,0,90)",
"math.clamp(math.sin(q.anim_time*90*2.5+225)*2,-90,0)"
],
"0.0": [-0.37, 2.61, -1.49],
"0.0417": [-0.37, 2.61, -1.49],
"0.125": [-0.3, 2.13, -1.22],
"0.25": [-0.2, 1.42, -0.81],
"0.375": [-0.1, 0.71, -0.4],
"0.5": [0, 0, 0],
"1.3333": [0, 0, 0],
"1.375": [
"math.clamp(math.sin(q.anim_time*90*2.5+225)*0.5,-90,0)",
"math.clamp(-math.sin(q.anim_time*90*2.5+225)*3.5,0,90)",
"math.clamp(math.sin(q.anim_time*90*2.5+225)*2,-90,0)"
]
"1.375": [0, 0, 0],
"1.5833": [-0.37, 2.61, -1.49]
}
},
"leg_right2": {
@@ -899,13 +910,13 @@
},
"body": {
"position": {
"0.0": [0, -2, "-math.sin(q.anim_time*90*1)*0.15"],
"0.4583": [0, -2, "-math.sin(q.anim_time*90*1)*0.15"],
"0.5417": [0, "-2.2+math.sin(q.anim_time*90*40)*0.4", "-math.sin(q.anim_time*90*1)*0.15"],
"0.6667": [0, -2, "-math.sin(q.anim_time*90*1)*0.15"],
"1.25": [0, -2, "-math.sin(q.anim_time*90*1)*0.15"],
"1.3333": [0, "-2.2+math.sin(q.anim_time*90*40)*0.4", "-math.sin(q.anim_time*90*1)*0.15"],
"1.4583": [0, -2, "-math.sin(q.anim_time*90*1)*0.15"]
"0.0": [0, -1, "-math.sin(q.anim_time*90*1)*0.15"],
"0.4583": [0, -1, "-math.sin(q.anim_time*90*1)*0.15"],
"0.5": [0, -1.3, "-math.sin(q.anim_time*90*1)*0.15"],
"0.5417": [0, -1, "-math.sin(q.anim_time*90*1)*0.15"],
"1.25": [0, -1, "-math.sin(q.anim_time*90*1)*0.15"],
"1.2917": [0, -1.3, "-math.sin(q.anim_time*90*1)*0.15"],
"1.3333": [0, -1, "-math.sin(q.anim_time*90*1)*0.15"]
}
},
"torso": {
@@ -1397,7 +1408,7 @@
}
},
"animation.exeggutor_alolan.blink3": {
"animation_length": 0.16667,
"animation_length": 0.1667,
"bones": {
"eyelid_right3": {
"position": {
@@ -1415,25 +1426,6 @@
}
}
},
"animation.exeggutor_alolan.new": {
"loop": true,
"bones": {
"body": {
"scale": 0.9
},
"neck11": {
"position": [0, -230, 0]
}
}
},
"animation.exeggutor_alolan.new2": {
"loop": true,
"bones": {
"body": {
"scale": 1.2
}
}
},
"animation.exeggutor_alolan.cry": {
"animation_length": 1.5,
"bones": {
@@ -1472,27 +1464,15 @@
"mouth_closed": {
"position": {
"0.0": [0, 0, -0.1],
"0.25": {
"pre": [0, 0, -0.1],
"post": [0, 0, 0]
},
"1.25": {
"pre": [0, 0, 0],
"post": [0, 0, -0.1]
}
"0.25": {"pre": [0, 0, -0.1], "post": [0, 0, 0]},
"1.25": {"pre": [0, 0, 0], "post": [0, 0, -0.1]}
}
},
"mouth_open": {
"position": {
"0.0": [0, 0, 0.1],
"0.25": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0]
},
"1.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
}
"0.25": {"pre": [0, 0, 0.1], "post": [0, 0, 0]},
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0.1]}
}
},
"head2": {
@@ -1506,27 +1486,15 @@
"mouth_closed2": {
"position": {
"0.0": [0, 0, 0],
"0.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0.2]
},
"1.25": {
"pre": [0, 0, 0.2],
"post": [0, 0, 0]
}
"0.25": {"pre": [0, 0, 0], "post": [0, 0, 0.2]},
"1.25": {"pre": [0, 0, 0.2], "post": [0, 0, 0]}
}
},
"mouth_open2": {
"position": {
"0.0": [0, 0, 0],
"0.25": {
"pre": [0, 0, 0],
"post": [0, 0, -0.1]
},
"1.25": {
"pre": [0, 0, -0.1],
"post": [0, 0, 0]
}
"0.25": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
"1.25": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
},
"head3": {
@@ -1540,27 +1508,15 @@
"mouth_closed3": {
"position": {
"0.0": [0, 0, -0.1],
"0.25": {
"pre": [0, 0, -0.1],
"post": [0, 0, 0]
},
"1.25": {
"pre": [0, 0, 0],
"post": [0, 0, -0.1]
}
"0.25": {"pre": [0, 0, -0.1], "post": [0, 0, 0]},
"1.25": {"pre": [0, 0, 0], "post": [0, 0, -0.1]}
}
},
"mouth_open3": {
"position": {
"0.0": [0, 0, 0.1],
"0.25": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0]
},
"1.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
}
"0.25": {"pre": [0, 0, 0.1], "post": [0, 0, 0]},
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0.1]}
}
},
"neck": {
@@ -515,8 +515,24 @@
"position": {
"0.0": [0, 0.2, 2],
"0.25": [0, 0, 5.4],
"0.4167": [0, "-0.5+math.clamp(math.sin(q.anim_time*90*2-0),0,1)*4", "-0.25+math.sin(q.anim_time*90*3+30)*4"],
"1.0417": [0, "0.5+math.clamp(math.sin(q.anim_time*90*2-0),0,1)*4", "math.sin(q.anim_time*90*3+10)*4"],
"0.4167": {
"pre": [0, 3.1, 2.35],
"post": [0, 3.1, 2.35],
"lerp_mode": "catmullrom"
},
"0.625": {
"post": [0, 3.41, -0.99],
"lerp_mode": "catmullrom"
},
"0.8333": {
"post": [0, 2.13, -3.54],
"lerp_mode": "catmullrom"
},
"0.9583": {
"post": [0, 1.09, -4.05],
"lerp_mode": "catmullrom"
},
"1.0417": [0, 0.55, -3.8],
"1.0833": [0, 0.5, -3.34552],
"1.5": [0, 0.2, 2]
}
@@ -37,9 +37,11 @@
"rotation": ["math.sin(q.anim_time*90*1.5-150)*1.5", 0, "math.sin(q.anim_time*90*1.5-60)*2"]
},
"stache": {
"position": [0, 0, 2],
"scale": 0
},
"lil_stache": {
"position": [0, -1, 0],
"scale": 0
}
}
@@ -244,9 +246,11 @@
}
},
"stache": {
"position": [0, 0, 2],
"scale": 0
},
"lil_stache": {
"position": [0, -1, 0],
"scale": 0
},
"body": {
@@ -290,9 +294,11 @@
"rotation": ["5+math.sin(q.anim_time*90*1.5-150)*1.5", 0, "math.sin(q.anim_time*90*1.5-60)*2"]
},
"stache": {
"position": [0, 0, 2],
"scale": 0
},
"lil_stache": {
"position": [0, -1, 0],
"scale": 0
}
}
@@ -343,9 +349,11 @@
"rotation": [-0.19072, "math.sin(q.anim_time*90*0.5-130)*-3", -4.75382]
},
"stache": {
"position": [0, 0, 2],
"scale": 0
},
"lil_stache": {
"position": [0, -1, 0],
"scale": 0
}
}
@@ -1712,9 +1720,11 @@
}
},
"stache": {
"position": [0, 0, 2],
"scale": 0
},
"lil_stache": {
"position": [0, -1, 0],
"scale": 0
}
}
@@ -2232,9 +2242,11 @@
}
},
"stache": {
"position": [0, 0, 2],
"scale": 0
},
"lil_stache": {
"position": [0, -1, 0],
"scale": 0
},
"mouth_open_happy": {
@@ -2531,9 +2543,11 @@
}
},
"stache": {
"position": [0, 0, 2],
"scale": 0
},
"lil_stache": {
"position": [0, -1, 0],
"scale": 0
}
}
@@ -2825,9 +2839,11 @@
}
},
"stache": {
"position": [0, 0, 2],
"scale": 0
},
"lil_stache": {
"position": [0, -1, 0],
"scale": 0
}
},
@@ -3597,9 +3613,11 @@
}
},
"stache": {
"position": [0, 0, 2],
"scale": 0
},
"lil_stache": {
"position": [0, -1, 0],
"scale": 0
},
"body": {

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