Compare commits

...
Author SHA1 Message Date
Apion 0dd0a78741 Cleaned up DamageInstruction 2025-03-23 15:05:31 -04:00
Hiroku 03ddc35d36 Merge branch 'Fix-pokemon-loadFrom' into 'main'
Fixed Pokemon.loadFrom[JSON/NBT]

Closes #1507

See merge request cable-mc/cobblemon!1571
2025-03-23 03:22:17 +00:00
ShiroFenixandHiroku 1b8e9b9b36 Fixed Pokemon.loadFrom[JSON/NBT] 2025-03-23 03:22:17 +00:00
Paul e52ac956f0 Added q.entity.is_holding_item for pokemon posers to use 2025-03-23 12:40:59 +10:00
Hiroku 493664bef2 Merge branch 'mealam/pokeballlocation' into 'main'
fix: Adjust `NPCEntity` pokeball throw positioning to account for `baseScale`

See merge request cable-mc/cobblemon!1568
2025-03-21 23:50:33 +00:00
AramandHiroku 981e3e5efc fix: Adjust NPCEntity pokeball throw positioning to account for baseScale 2025-03-21 23:50:33 +00:00
Hiroku c15350e647 Merge branch 'mealam/1499' into 'main'
fix: Adjust `NPCEntity` beam positioning to account for `baseScale`

Closes #1499

See merge request cable-mc/cobblemon!1567
2025-03-20 00:36:12 +00:00
AramandHiroku f9e5784b10 fix: Adjust NPCEntity beam positioning to account for baseScale 2025-03-20 00:36:12 +00:00
Hiroku 2f4b861f98 Merge branch 'implement_pokemon' into 'main'
Dragonite and Gyarados models with locators for testing on main

See merge request cable-mc/cobblemon!1564
2025-03-16 00:20:05 +00:00
Frank The FarmerandHiroku a7022268c1 Dragonite and Gyarados models with locators for testing on main 2025-03-16 00:20:05 +00:00
Hiroku 3082600e11 Merge branch 'meowscarada-fix' into 'main'
Fixed Meowscarada's resolver having the wrong name

See merge request cable-mc/cobblemon!1562
2025-03-15 08:48:41 +00:00
gruxor a348cfd338 Fixed Meowscarada's resolver having the wrong name 2025-03-15 04:19:38 -04:00
Paul 35bfc7bf6c Merge remote-tracking branch 'origin/main' 2025-03-15 13:22:28 +10:00
Paul ae87c3dd84 Fixed downward correction of spawning, closes #1498 2025-03-15 13:22:04 +10:00
Hiroku d944803571 Merge branch 'jackowes/concrete_jet/01' into 'main'
Full Base Jet Controller

See merge request cable-mc/cobblemon!1560
2025-03-15 01:14:00 +00:00
Jackson BowesandHiroku 2c3b474c01 Full Base Jet Controller 2025-03-15 01:13:59 +00:00
Paul c2538560e1 Added check for activate_ action effects, implemented protect blocking effect 2025-03-14 10:23:50 +10:00
Paul d10c058c74 Added properties map to posers and look for item display contexts from there as a first try for item rendering 2025-03-14 09:55:31 +10:00
Paul d1b6d95d57 Fixed interpolation being applied to full model transformed parts 2025-03-14 09:17:34 +10:00
Paul 977387a184 Merge remote-tracking branch 'origin/main' 2025-03-13 20:26:35 +10:00
Paul 69bbc09d6a Updated fabric version, fixed our is_overworld including end biomes 2025-03-13 20:26:23 +10:00
Hiroku 46b04ad462 Merge branch 'async-player-data-saving' into 'main'
Moved player data saving to do the heavier work on a worker thread,...

See merge request cable-mc/cobblemon!1559
2025-03-13 05:03:28 +00:00
Paul a1b6fd3d1a Fixed silent pokemon still playing shiny sounds and particles, closes #1316 2025-03-13 11:19:10 +10:00
Paul fb9ed28b74 Moved player data saving to do the heavier work on a worker thread, potentially fixing storages not saving in race conditions 2025-03-13 11:01:51 +10:00
Paul 4bfc2a97dd Fixed base entity functions not being added to pokemon structs, messing with a lot of things 2025-03-13 09:47:12 +10:00
Nick a2cf66fbc1 Merge branch 'seat-generator' into 'main'
Seat generator

See merge request cable-mc/cobblemon!1558
2025-03-12 16:10:03 -07:00
HirokuandNick 5bda81a5c4 Seat generator 2025-03-12 16:10:03 -07:00
Test 32ccd15121 biome test bg 2025-03-12 03:56:25 +00:00
Hiroku a51cda998b Merge branch 'Adainish-main-patch-50806' into 'main'
Fixes a deserialisation issue due to IVS/EVS being required

See merge request cable-mc/cobblemon!1557
2025-03-12 02:25:20 +00:00
Adenydd Stuut || Winglet 9dc14eff7c Edit PokemonProperties.kt 2025-03-12 01:48:15 +00:00
Hiroku 4b1690c62e Merge branch 'observe-less' into 'main'
Removed heaps of observables from Pokemon because they weren't needed and it added heaps to the RAM

See merge request cable-mc/cobblemon!1555
2025-03-11 22:57:49 +00:00
Hiroku d02251b67d Edit CHANGELOG.md 2025-03-11 11:57:07 +00:00
Hiroku 54c8cbfbe8 Merge branch 'unlockable-wallpapers' into 'main'
Added unlockable PC box wallpapers

See merge request cable-mc/cobblemon!1525
2025-03-11 09:49:11 +00:00
Paul 2d8ce63dcd Changelog 2025-03-11 15:53:02 +10:00
Paul 1a92af2cd6 Removed heaps of observables from Pokemon because they weren't needed and it added heaps to the RAM 2025-03-11 15:51:45 +10:00
Paul 7e088bdeec @JvmStatic on all the permissions so the interop isn't whack 2025-03-11 13:30:01 +10:00
Paul 6142049d51 Added uuid function to pokemonStore molang 2025-03-11 12:57:38 +10:00
Hiroku d031f339c6 Merge branch 'spawning-improvements' into 'main'
Spawning performance improvements

See merge request cable-mc/cobblemon!1553
2025-03-10 11:33:39 +00:00
Paul 3ddbc9b313 Unmark wallpapers as new once you try them 2025-03-10 20:59:42 +10:00
Paul dd2c1ddbc6 Regenerate the validBiomes lists when data is reloaded (yknow, for when that works) 2025-03-10 20:34:31 +10:00
Paul badd7e8c2e Merge remote-tracking branch 'origin/main' into spawning-improvements 2025-03-10 20:27:48 +10:00
Paul d7c4380cc2 oop 2025-03-09 20:09:00 +10:00
Paul 7fc26ab939 Fixed held items being given with "Air" as the name oops 2025-03-09 14:50:08 +10:00
Paul 37f430ddf7 Fixed issues with unseen wallpapers not communicating properly to the client 2025-03-09 14:42:29 +10:00
Hiroku f0a2182149 Merge branch 'riding-settings' into 'main'
Added riding config options and implemented the invert mouse options on current controllers.

See merge request cable-mc/cobblemon!1550
2025-03-09 04:14:47 +00:00
Paul 9605775f1e Merge remote-tracking branch 'origin/main' into spawning-improvements 2025-03-09 11:00:56 +10:00
Paul f251bc20c1 Fixed species feature lookups not targeting code features first because of a funnybug 2025-03-09 11:00:29 +10:00
Paul a02b3d74b8 Fixed species additions not being able to add implemented, closes #779 2025-03-09 10:58:18 +10:00
Paul 7f3a4c20b3 Added biome precalculation to the spawning system, improved RegistryLikeCondition performance 2025-03-09 10:39:10 +10:00
Hiroku e76999c611 Merge branch 'Fix-NPCs-using-pokemon-outside-Pool' into 'main'
Fixing NPCs using pokemon outside of their Pool

Closes #1482

See merge request cable-mc/cobblemon!1552
2025-03-07 23:30:04 +00:00
WhiteFenix19 c2771bcb95 Fixed Formatting 2025-03-07 19:27:51 -04:00
WhiteFenix19 5b858b5982 Merge remote-tracking branch 'origin/Fix-NPCs-using-pokemon-outside-Pool' into Fix-NPCs-using-pokemon-outside-Pool 2025-03-07 17:09:29 -04:00
WhiteFenix19 7082220e29 Fixed NPCs using Pokémon outside of their pool when a Pokémon name had a typo. (Fixed indentations) 2025-03-07 17:08:52 -04:00
WhiteFenix19 1a87830a52 Fixed NPCs using Pokémon outside of their pool when a Pokémon name had a typo. 2025-03-07 17:02:54 -04:00
WhiteFenix19 9eff6dcced Fixed NPCs using Pokémon outside of their pool when a Pokémon name had a typo. 2025-03-07 15:05:48 -04:00
WhiteFenix19 52690c3aa6 Added check to avoid random Pokémon on Pool, added warning if species wrong or party empty 2025-03-07 13:59:40 -04:00
Paul 8f0780c5f6 I'm autistic 2025-03-07 12:34:59 +10:00
Test 465a7fbe73 update changelog, alt icons for descending sort 2025-03-05 17:47:42 -05:00
Hiroku 6b5abfa319 Merge branch 'fix-interpolation' into 'main'
Fixed interpolation breaking with non emissive textures

See merge request cable-mc/cobblemon!1551
2025-03-05 11:31:37 +00:00
Paul 39197adebb Why'd I format that like that 2025-03-05 18:45:00 +10:00
BuildTools 4b1e192705 Fixed interpolation breaking with non emmisive textures 2025-03-05 10:32:54 +02:00
Test a3fa3d4b82 Merge branch 'unlockable-wallpapers' of https://gitlab.com/cable-mc/cobblemon into unlockable-wallpapers 2025-03-05 02:44:32 -05:00
Test c5ad7a0fb7 refactor pc updates 2025-03-05 02:44:11 -05:00
Paul d17f94c0d6 Reworked way pokemon are blocked from spawning on rails to not be as intensive 2025-03-05 14:27:02 +10:00
JPAK 398bff4c15 Fix some formatting. 2025-03-03 20:48:45 -06:00
JPAK e0655df5f0 Merge remote-tracking branch 'origin/riding-settings' into riding-settings
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/api/riding/controller/RideController.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/pokemon/riding/controllers/BirdAirController.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/pokemon/riding/controllers/HelicopterAirController.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/pokemon/riding/controllers/JetAirController.kt
2025-03-03 20:44:58 -06:00
JPAK 9174aac64c Added Config options and implemented the invert mouse options on current controllers. 2025-03-03 20:43:35 -06:00
JPAK 3cdc4c7d97 Added Config options and implemented the invert mouse options on current controllers. 2025-03-03 17:35:32 -06:00
Polymeta 9ce6acc44d Merge branch 'fix-hide-additional-tooltip' into 'main'
hide_additional_tooltip working for Pokerod and Bait

See merge request cable-mc/cobblemon!1547
2025-03-03 08:44:49 +00:00
Polymeta f170ed726b Merge branch 'jackowes/riding/02' into 'main'
Fix: Whole json object being passed to deserialize rather than the single JsonElement.

See merge request cable-mc/cobblemon!1549
2025-03-02 18:11:14 +00:00
JacksonB 979d6f02a6 Fix: Whole json object being passed to deserialize rather than the single JsonElement. 2025-03-02 11:32:38 -06:00
BuildTools 3fbe80cb1a Changelog 2025-03-02 17:02:07 +02:00
Polymeta 8fdb32273d Merge branch 'nuggets-of-nuggets' into 'main'
Fling

See merge request cable-mc/cobblemon!1548
2025-03-02 13:11:56 +00:00
dhi_holo d5c9d8d5b1 Fling
Blocks of Gold now can be flung for 150 BP
2025-03-02 20:57:37 +10:00
BuildTools 752c9c234e hide_additional_tooltip working for Pokerod and Bait 2025-03-02 12:10:28 +02:00
Hiroku b7b6185ada Merge branch 'jackowes/ride_cleanup' into 'main'
WIP jet, bird, and helicopter controller

See merge request cable-mc/cobblemon!1543
2025-03-02 09:31:46 +00:00
Jackson BowesandHiroku 211b886bf3 WIP jet, bird, and helicopter controller 2025-03-02 09:31:45 +00:00
Paul 36d1008f29 Minor code cleanup and added interpolate property to changelog 2025-03-02 15:39:02 +10:00
Hiroku 1441625a6b Merge branch 'animated-texures-interpolation' into 'main'
Animated Texture Interpolation for Cobblemon

See merge request cable-mc/cobblemon!1545
2025-03-02 05:28:00 +00:00
Paul 3859eb574e Another tweak for Polymeta 2025-03-02 15:25:12 +10:00
Paul b4a29214a7 Minor changes to unlockable wallpapers code for Poly's happiness 2025-03-02 15:24:05 +10:00
Apion 0fb5d4f69b Merge branch 'riding-sheet-scraper' into 'main'
Added scraper for riding sheet

See merge request cable-mc/cobblemon!1546
2025-03-01 08:34:14 +00:00
Gertimoshka 6ca16a0161 Resolve Conflicts 2025-03-01 03:46:18 +00:00
Paul e4346687fc Added scraper for riding sheet 2025-03-01 10:51:04 +10:00
BuildTools 2f31db2232 Insane Person Presents: INTERPOLATION 2025-02-27 18:04:48 +02:00
Polymeta e0f26923b7 Merge branch 'moe-eats-bugs' into 'main'
Fix logic for LevelUpCriterion

See merge request cable-mc/cobblemon!1544
2025-02-26 13:08:30 +00:00
MoeBoy76andPolymeta 52cff9472a Fix logic for LevelUpCriterion 2025-02-26 13:08:30 +00:00
Test ed0e0fc65a Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into unlockable-wallpapers 2025-02-23 11:04:13 -05:00
Polymeta c4935c3128 Merge branch 'feat/animated-party-portraits' into 'main'
Add support for animated portraits in the party overlay

See merge request cable-mc/cobblemon!1302
2025-02-23 09:26:59 +00:00
Hiroku 7831421399 Merge branch 'feature/cosmetic-slot' into 'main'
Cosmetic item

See merge request cable-mc/cobblemon!1538
2025-02-23 09:11:15 +00:00
TestandHiroku a059979220 Cosmetic item 2025-02-23 09:11:15 +00:00
Hiroku 09bab5b2aa Merge branch 'means-of-transportation' into 'main'
Rhydon the Pokemon

See merge request cable-mc/cobblemon!1534
2025-02-21 22:45:15 +00:00
Paul 358d2604fb imports 2025-02-22 08:34:17 +10:00
Paul bbd0415c92 Removed unused packet 2025-02-22 08:33:47 +10:00
Paul 9f553fc6c1 Remove blank mixin 2025-02-22 08:22:25 +10:00
Polymeta 51f8bb6ad5 Merge branch 'fix-pokeball-spewpa-evo' into 'main'
Fixed field name in evolution requirements for Spewpa Pokeball.

See merge request cable-mc/cobblemon!1541
2025-02-21 11:40:23 +00:00
Deltric cf93c0d544 Update changelog 2025-02-21 05:25:12 -06:00
Paul 2e6bef608b Merge remote-tracking branch 'origin/main' 2025-02-21 20:22:54 +10:00
Paul dcba7a5ab7 Removed unnecessary berry validation now that resultant yields are capped 2025-02-21 20:22:27 +10:00
Hiroku 4e3b1eb641 Merge branch 'feature/fix-ghost-pokemon' into 'main'
remove owned pokemon immediately when player stops seeing them, instead of queuing them

Closes #1127

See merge request cable-mc/cobblemon!1528
2025-02-21 10:21:43 +00:00
Paul 6f949ce858 Fixed no sounds playing for status curing berries being eaten or battle-interacted healing berries being eaten 2025-02-21 20:20:38 +10:00
Paul a04cd3162a Merge remote-tracking branch 'origin/main' into means-of-transportation
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/pokemon/PokemonRenderer.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/pokemon/Pokemon.kt
2025-02-21 17:48:24 +10:00
Paul 8b551159a6 Removed things that shouldn't have been there, client-packaged various client mixins 2025-02-21 17:46:46 +10:00
Hiroku 05b8621a81 Merge branch 'gradle/reposilite' into 'main'
Reposilite maven publication endpoint

See merge request cable-mc/cobblemon!1537
2025-02-21 03:14:39 +00:00
Paul 1068d3e078 Fixed berry yield exceeding growth points, closes #1435 2025-02-21 12:51:20 +10:00
Hiroku c1d6a9563c Merge branch 'feature/modfile-versions' into 'main'
Modfile tweaks and small mixin fixes

Closes #1460 and #1456

See merge request cable-mc/cobblemon!1539
2025-02-21 00:28:37 +00:00
PolymetaandHiroku f426b16f1d Modfile tweaks and small mixin fixes 2025-02-21 00:28:37 +00:00
Hiroku c944fc1ac6 Merge branch 'fix/form-change-illegal-moves' into 'main'
fix: Pokemon will now properly update their moveset after form changes

See merge request cable-mc/cobblemon!1540
2025-02-21 00:27:48 +00:00
Paul c5dcfc57ea Added toast for unlocking PC wallpapers, fixed some molang issues for living entities 2025-02-21 10:26:13 +10:00
Deltric c68df830a7 Fixed field name in evolution requirements for Spewpa Pokeball. 2025-02-19 19:37:44 -06:00
Ina 0432441868 fix: Pokemon will now properly update their moveset after form changes 2025-02-19 22:52:23 +00:00
Ina dcd0959600 chore: MR renamed feedback 2025-02-19 20:47:12 +00:00
Nick 7f631174d7 Use native snapshot extension 2025-02-17 14:27:05 -08:00
Nick 379344036f Reposilite maven publication endpoint 2025-02-17 14:24:20 -08:00
Paul 9997a5c4b4 Touch-ups to wallpaper unlocked flow and the right click platform event flows 2025-02-17 20:29:43 +10:00
Paul 2b70e5614c Merge remote-tracking branch 'origin/main' into unlockable-wallpapers
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonFlows.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/molang/MoLangFunctions.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/events/FlowHandler.kt
2025-02-17 20:18:29 +10:00
Paul 759f0800cd Added MoLang flows for poke_ball_capture_calculated, evolution_tested, evolution_accepted, evolution_completed, cleaned up a collection of MoLang hooks from PokemonProperties and spawning 2025-02-17 20:08:49 +10:00
Paul 0ed0270d18 Merge remote-tracking branch 'origin/main' 2025-02-17 16:42:05 +10:00
Paul 324658b765 Added referential data for riding stats 2025-02-17 14:44:06 +10:00
Hiroku 478e714a2d Merge branch 'held-item-rending-fix' into 'main'
Visual Held Items Rending Fix

See merge request cable-mc/cobblemon!1536
2025-02-17 03:13:38 +00:00
Josh 6005c04e64 There was an issue with rendering items in the original visual held items branch that wasn't properly reverted. If multiple pokemon where being rendered with different item display contexts it would prioritize one, ignoring the other. This fixes that. 2025-02-16 21:16:48 -05:00
Paul 4f1517e336 Adding molang context and functions to poke ball capture event 2025-02-16 10:07:14 +10:00
Test 589c5381e2 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into unlockable-wallpapers 2025-02-15 15:14:40 -05:00
Test 4539703497 prevent filenotfoundexception; update colors 2025-02-15 15:14:23 -05:00
Paul b4ef516626 Conflicts can be harmful in large doses 2025-02-15 21:56:34 +10:00
Paul 2cf2afd321 Merge remote-tracking branch 'origin/main' into means-of-transportation
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonNetwork.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/pokemon/PokemonSpecies.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/PokemonEntity.kt
2025-02-15 21:44:01 +10:00
JPAK bfaf7c8034 Pitch extremes are no longer funky. Locators use Rollable's orientation when appropriate 2025-02-13 16:48:08 -06:00
JPAK 833e814adf Clean up some mixins and move some stuff around. 2025-02-13 14:11:06 -06:00
JPAK 2ee84067cc When riding pokemon no longer moves head if RideManager has shouldRotatePokemonHead return false. 2025-02-13 12:46:13 -06:00
JPAK 3bec9c6695 When riding player no longer moves head if RideController has shouldRotatePlayerHead false. 2025-02-12 19:20:52 -06:00
JPAK 620f2153fd Add comments and undo seat positioning properly. 2025-02-12 16:49:14 -06:00
JPAK 2f05be31ca A bunch of changes to make locators work. The main thing is that undoing the seat positioning is "delayed" or just not lerped properly in PlayerRendererHook.kt. 2025-02-12 14:56:35 -06:00
Ina 7210063026 feat: Add config support for this system 2025-02-12 20:10:16 +00:00
Ina 94e52f6f82 Merge branch 'main' into feat/animated-party-portraits
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/client/gui/PartyOverlay.kt
2025-02-12 18:49:15 +00:00
Polymeta 0d311593cc remove owned pokemon immediately when player stops seeing them, instead of queuing them
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-02-11 11:12:13 +00:00
JPAK 0013b1cba8 Want to get approval on this since it touches other areas, but it does fix locators. 2025-02-10 21:54:41 -06:00
Paul 0152bc2e32 Added event for unlocking wallpapers, added flows for advancement_earned, right_clicked_entity, right_clicked_block, player_died, wallpaper_unlocked 2025-02-10 18:13:27 +10:00
Paul e175c44118 Added unlockable PC box wallpapers 2025-02-10 15:36:46 +10:00
JPAK 6d08f227c1 Hopefully fixing jittery stuff. Still some weirdness with the seats but I think the charizard seats are just wrong tbh 2025-02-08 21:36:04 -06:00
JPAK 64a543ca38 Player now moves to locator instead of seat position. Also move code out of PlayerRendererMixin to PlayerRendererHook.kt. Hitbox is still based on seat on serverside. 2025-02-08 14:25:07 -06: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
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
JPAK e44eb3f77f Fix rotations and player positioning on the ground. 2025-01-23 13:46:30 -06:00
Guilherme Pereira 6027934c22 add glider air controller 2025-01-23 05:17:37 -03: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
Ina 0da8243f05 fix: Missing return 2024-11-17 19:38:03 +00:00
Ina 2774360d4c feat: Add system to draw animated (or not) portraits based on graphics settings. 2024-11-17 19:34:49 +00: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
519 changed files with 20714 additions and 1727 deletions
+17 -12
View File
@@ -1,16 +1,21 @@
### Additions
- Added ability to rename PC Boxes by clicking on the name of a box
- Added ability to set wallpapers per PC Box by clicking the button right to the box name
- Added sorting by Name, Level and type by clicking the button left of the box name (shift reverses order)
- Added filtering/search functionality in PC UI, which also supports pokemon properties (e.g. shiny=yes shows all shinies)
- Added /changewallpaper <player> <boxNumber> <wallpaper> command to change a wallpaper through commands
- Added /renamebox <player> <boxNumber> <name> command to rename a PC box through commands
- Added ability to rename PC Boxes by clicking on the name of a box.
- Added box options buttons for boxes, toggleable by clicking the right icon button in the bottom bar.
- The button on the right allows for changing the box wallpaper.
- The option buttons on the left side allow for sorting the box by name, level, Pokédex number, gender, and type. Shift clicking allows for sorting in reverse order.
- Added filter functionality in PC UI, which supports `PokemonProperties` (e.g. `shiny=yes` shows all shiny Pokémon).
- Added `/changewallpaper <player> <boxNumber> <wallpaper>` command to change a box wallpaper through commands.
- Added `/renamebox <player> <boxNumber> <name>` command to rename a PC box through commands.
### Developer
- Added `RenamePCBoxEvent.Pre` and `RenamePCBoxEvent.Post` events to prevent players from renaming a box or changing their input.
- Added `ChangePCBoxWallpaperEvent.Pre` and `ChangePCBoxWallpaperEvent.Post` to prevent players from changing wallpapers or changing their selection.
- Added `WallpaperCollectionEvent` which gets called when clients connect to a server, allowing the server to handle which of the client-found wallpapers it's allowed to move (collected wallpapers can be removed for example to make it "vanish" client-side).
- Added `WallpaperUnlockedEvent`.
- Renamed `SetPCBoxPokemonPacket` and the respective handler to `SetPCBoxPacket`.
- Added RenamePCBoxEvent.Pre/Post events to prevent players from renaming a box or change their input
- Added ChangePCBoxWallpaperEvent.Pre/Post to prevent players from changing to a wallpaper or change their selection
- Added WallpaperCollectionEvent which gets called when clients connect to a server, allowing the server which of the clients found wallpapers it's allowed to move (collected wallpapers can be removed for example to make it "vanish" client-side)
- Wallpapers are loaded from `assets/<namespace>/textures/gui/pc/wallpaper/` and all wallpapers in this folder are available to the client to choose by default
- Renamed `SetPCBoxPokemonPacket` and the respective handler to `SetPCBoxPacket`
### Addons
- Added Flows for `player_tick_pre`, `player_tick_post`, `advancement_earned`, `right_clicked_entity`, `right_clicked_block`, `player_died`, `wallpaper_unlocked`.
- Flows now have `q.` for any context properties in addition to the `c.` properties, making it a bit more convenient when calling other scripts from Flows.
- Added `unlockable_pc_box_wallpapers` datapack folder for wallpapers that need to be unlocked before they're usable.
- Wallpapers are loaded from `assets/<namespace>/textures/gui/pc/wallpaper/` and all wallpapers in this folder are available to the client to choose by default.
+4
View File
@@ -0,0 +1,4 @@
### Additions
- Added the ability to ride Pokémon by shift-right clicking and selecting the ride option.
- Added /calculateseatpositions command for approximating hitbox locations for riding configurations.
+32 -3
View File
@@ -7,10 +7,16 @@
- Added `blacklisted_items_to_hold` and `whitelisted_items_to_hold` tags to allow for controlling which items players can give to their Pokémon. If the whitelist is empty, it will consider all item as allowed (unless they are in the blacklist).
- Pokémon now follow the mouse cursor on the Summary screen, with an option to disable this in the settings.
- Pokémon's held items can now be rendered, with a visibility toggle in the Summary screen.
- Added cosmetic item functionality for Pokémon. Certain cosmetic items can be given to applicable Pokémon via the interact menu.
- Added the various log blocks as cosmetic items for Timburr and Komala.
- Added `visibility/hidden`, `visibility/hat` and `visibility/face` tags to control where and how certain items are rendered.
### Changes
- Renamed `chargeGainedPerTick` config to `secondsToChargeHealingMachine`.
- Made Blocks of Gold count as Big Nuggets when held by a Pokémon (for Fling functionality)
- Substantially optimised spawning checks mainly by front-loading biome filtering.
- When using the `cobblemon` or `generation_9` capture calculators a critical capture with a single shake will always play for successful captures when you've already registered the Pokémon as caught in your Pokédex.
- Improved the performance of saving Pokédex and player data.
### Fixes
- Fixed Particles sometimes facing the wrong direction (looking at you, Swords Dance)
@@ -24,6 +30,20 @@
- Fixed evolutions sometimes preventing players from logging in to servers
- Fixed rendering of shoulder-mounted Pokémon desyncing between clients
- Fixed apricorn chest boats forgetting their inventories when being unloaded
- Fixed moves not updating correctly between form changes resulting in illegal movesets
- Fixed crash sometimes occurring with the "Oritech" mod
- Fixed crashes due to an incorrect Java version handing out an obscure crash.
- Fixed some berries being able to rarely get too many berries and cause a crash.
- Fixed status curing berries not playing the berry eating sound, same for healing berries used mid-battle.
- Fixed owned Pokémon sometimes being un-interactable after the player relogs fast
- Fixed field name in evolution requirements for Spewpa Pokeball.
- Fixed LevelUpCriterion logic to correctly check that the Pokémon is a preEvo.
- Fixed `hide_additional_tooltip` vanilla flag not properly hiding tooltips on pokerod and bait items
- Fixed NPCs using Pokémon outside of their pool when a Pokémon name had a typo.
- Fixed an issue with datapacked species features not being applied properly when relogging.
- Fixed Pokémon marked as silent still playing shiny sounds and effects.
- Fixed an issue with newer versions of Fabric API where underground Pokémon were spawning in The End.
- Fixed spawning not working well when you're at high points surrounded by lower altitude spawning areas, such as flying.
### Developer
- A finished battle now has winners and losers set inside of `PokemonBattle` instead of them always being empty.
@@ -34,14 +54,23 @@
- Removed the NbtItemPredicate class, all the mod usages now use the vanilla item predicate solution, this causes breaking changes on Fossil, HeldItemRequirement & ItemInteractionEvolution
- Renamed Cobblemon's creative tabs to start with "Cobblemon: " to distinguish Cobblemon's tabs from tabs for other mods.
- Various items now have a rarity value.
- Reworked observable handling in `Pokemon.kt` to cut down on RAM usage and clarify the file.
- Note: This will break mods that used our observable functionality there or in MoveSet, IVs, EVs, or BenchedMoves.
- Using `Pokemon#onChange()` is now the way to mark a Pokémon as needing a save.
- Using `[Pokemon].changeObservable` is now the way to get an `Observable` for any save-worthy changes.
- Updated NPCEntity beam positioning to properly account for the baseScale property.
- Updated NPCEntity pokeball throw positioning to properly account for the baseScale property.
- Fixed `[Pokemon].copyFrom` error causing forms, IVs, and EVs to not be applied properly when using `[Pokemon].loadFromJSON` or `[Pokemon].loadFromNBT`
### Changes
- When using the `cobblemon` or `generation_9` capture calculators a critical capture with a single shake will always play for successful captures when you've already registered the Pokémon as caught in your Pokédex.
### MoLang & Datapacks
- The following usages for item predicates can now use item conditions like advancements do, you can learn about them in the [Minecraft wiki](https://minecraft.wiki/w/Advancement_definition#minecraft:filled_bucket)
- The `requiredContext` for an item interaction evolution
- The `itemCondition` for a held item evolution requirement
- The `fossils` for a fossil entry
- Added MoLang flows for `poke_ball_capture_calculated`, `evolution_tested`, `evolution_accepted`, `evolution_completed`
- Added `interpolate` boolean property to animated textures to allow gradual colour changes between frames.
- Fixed species additions not being capable of changing implemented status.
- Added support for action effects that are triggered by `|-activate|` Showdown instructions. `activate_{effect_id}` is the syntax.
## [1.6.1 (January 26th, 2025)](#1-6-1)
@@ -2162,4 +2191,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,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;
import net.minecraft.util.Mth;
import net.minecraft.util.SmoothDouble;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix3f;
import org.joml.Vector3f;
import java.util.function.Function;
public interface Rollable {
// From Minecraft's Camera
Vector3f FORWARDS = new Vector3f(0.0F, 0.0F, -1.0F);
Vector3f UP = new Vector3f(0.0F, 1.0F, 0.0F);
Vector3f LEFT = new Vector3f(-1.0F, 0.0F, 0.0F);
@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 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 getYaw() {
return (float) Mth.wrapDegrees(-Math.toDegrees(FORWARDS.angleSigned(getForwardVector(), UP)) + 180);
}
/**
* @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 getPitch() {
return (float) Mth.wrapDegrees(-Math.toDegrees(Math.asin(getForwardVector().y)));
}
/**
* @return 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() {
//Cobblemon.LOGGER.info("{}", (float) Math.toDegrees(getUpVector().angleSigned(UP, getForwardVector())));
return (float) Mth.wrapDegrees(-Math.toDegrees(getUpVector().angleSigned(UP, getForwardVector())));
}
/**
* Get the angular velocity in degrees per second as a Vec3
*/
Vec3 angRollVel( double deltaTime );
public Vec3 rotationOnMouseXY(
double yMouse,
double xMouse,
SmoothDouble yMouseSmoother,
SmoothDouble xMouseSmoother,
double sensitivity,
double deltaTime
);
boolean shouldRoll();
boolean useAngVelSmoothing();
void clearRotation();
}
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import net.minecraft.client.player.LocalPlayer;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
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.CallbackInfoReturnable;
@Mixin(LocalPlayer.class)
public abstract class LocalPlayerMixin {
@Shadow
private float jumpRidingScale;
@Inject(method = "getJumpRidingScale", at = @At("HEAD"), cancellable = true)
public void modifyJumpRidingScale(CallbackInfoReturnable<Float> cir) {
LocalPlayer player = (LocalPlayer) (Object) this;
if (player.isPassenger() && player.getVehicle() instanceof PokemonEntity) {
PokemonEntity ride = (PokemonEntity) player.getVehicle();
//Use custom jump bar logic if the current ride does not jump using it.
if( !ride.getRiding().canJump(ride, player))
{
cir.setReturnValue(ride.setRideBar());
}
}
}
}
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.platform.events.PlatformEvents;
import com.cobblemon.mod.common.platform.events.ServerPlayerEvent;
import net.minecraft.advancements.AdvancementHolder;
import net.minecraft.server.PlayerAdvancements;
import net.minecraft.server.level.ServerPlayer;
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.CallbackInfoReturnable;
@Mixin(PlayerAdvancements.class)
public class PlayerAdvancementsMixin {
@Shadow private ServerPlayer player;
@Inject(method = "award", at = @At(value = "INVOKE", target = "Lnet/minecraft/advancements/AdvancementRewards;grant(Lnet/minecraft/server/level/ServerPlayer;)V"))
private void cobblemon$award(AdvancementHolder advancement, String criterionKey, CallbackInfoReturnable<Boolean> cir) {
PlatformEvents.SERVER_PLAYER_ADVANCEMENT_EARNED.emit(new ServerPlayerEvent.AdvancementEarned(player, advancement));
}
}
@@ -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,11 +29,16 @@ 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;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.SmoothDouble;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
@@ -38,14 +46,18 @@ 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 net.minecraft.world.phys.Vec3;
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;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@@ -53,10 +65,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 +87,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_);
@@ -167,8 +181,7 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
@Inject(method = "isInvulnerableTo", at = @At("HEAD"), cancellable = true)
public void isInvulnerableTo(DamageSource source, CallbackInfoReturnable<Boolean> ci) {
if (!level().isClientSide) {
ServerPlayer player = (ServerPlayer)(Object)this;
if (!level().isClientSide && (Object) this instanceof ServerPlayer player) {
boolean invulnerableInBattle = this.level().getGameRules().getBoolean(CobblemonGameRules.BATTLE_INVULNERABILITY);
boolean inBattle = Cobblemon.INSTANCE.getBattleRegistry().getBattleByParticipatingPlayer(player) != null;
if (invulnerableInBattle && inBattle) {
@@ -225,4 +238,136 @@ 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) {
//Disabled to allow non mouse inputs to modify roll
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());
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 Vec3 rotationOnMouseXY(
double yMouse,
double xMouse,
SmoothDouble yMouseSmoother,
SmoothDouble xMouseSmoother,
double sensitivity,
double deltaTime
) {
LocalPlayer player = Minecraft.getInstance().player;
if (!this.equals(player)) return Vec3.ZERO;
var playerVehicle = player.getVehicle();
if (playerVehicle == null) return Vec3.ZERO;
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return Vec3.ZERO;
return pokemonEntity.getRiding().rotationOnMouseXY(
pokemonEntity,
player,
yMouse,
xMouse,
yMouseSmoother,
xMouseSmoother,
sensitivity,
deltaTime
);
}
@Override
public boolean useAngVelSmoothing() {
LocalPlayer player = Minecraft.getInstance().player;
if (!this.equals(player)) return true;
var playerVehicle = player.getVehicle();
if (playerVehicle == null) return true;
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return true;
return pokemonEntity.getRiding().useAngVelSmoothing(pokemonEntity);
}
@Override
public Vec3 angRollVel( double deltaTime ) {
var ret = new Vec3(0.0, 0.0, 0.0);
LocalPlayer player = Minecraft.getInstance().player;
if (!this.equals(player)) return ret;
var playerVehicle = player.getVehicle();
if (playerVehicle == null) return ret;
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return ret;
return pokemonEntity.getRiding().angRollVel( pokemonEntity, player, deltaTime );
}
@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);
}
}
@@ -1,28 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.client.render.ClientPlayerIcon;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(PlayerRenderer.class)
public class PlayerRendererMixin {
@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);
}
}
@@ -9,8 +9,10 @@
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.client.CobblemonClient;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.player.LocalPlayer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@@ -30,5 +32,13 @@ public class AbstractClientPlayerMixin {
if (usageContext.getScanningGuiOpen()) {
cir.setReturnValue(usageContext.getFovMultiplier());
}
LocalPlayer player = (LocalPlayer) (Object) this;
if (player != null && player.isPassenger() && player.getVehicle() instanceof PokemonEntity) {
PokemonEntity ride = (PokemonEntity) player.getVehicle();
//Return custom fov mult
cir.setReturnValue(ride.rideFovMult());
}
}
}
@@ -0,0 +1,97 @@
/*
* 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.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 @Final private static float DEFAULT_CAMERA_DISTANCE;
@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());
}
}
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker;
import net.minecraft.client.DeltaTracker;
@@ -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.client;
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);
}
}
}
@@ -6,18 +6,22 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.Rollable;
import com.cobblemon.mod.common.item.PokedexItem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.ItemInHandRenderer;
import net.minecraft.client.renderer.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 +31,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);
}
}
}
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.Cobblemon;
import com.cobblemon.mod.common.ModAPI;
@@ -40,7 +40,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
*/
@Mixin(ItemRenderer.class)
public abstract class ItemRendererMixin {
@Unique private final String MODEL_PATH = Cobblemon.implementation.getModAPI() == ModAPI.FABRIC ? "fabric_resource" : "standalone";
// ignore the hint saying implmentation is never null, if something crashes then it is null and causes red herrings
@Unique private final String MODEL_PATH = (Cobblemon.implementation != null && Cobblemon.implementation.getModAPI() == ModAPI.FABRIC) ? "fabric_resource" : "standalone";
@Shadow @Final private ItemModelShaper itemModelShaper;
@@ -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()));
}
}
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.client.CobblemonBakingOverrides;
import java.util.List;
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Bone;
import com.cobblemon.mod.common.client.render.models.blockbench.repository.RenderContext;
@@ -6,33 +6,41 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
package com.cobblemon.mod.common.mixin.client;
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;
import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
import com.llamalad7.mixinextras.sugar.Local;
import com.mojang.blaze3d.Blaze3D;
import net.minecraft.client.Minecraft;
import net.minecraft.client.MouseHandler;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.util.Mth;
import net.minecraft.util.SmoothDouble;
import net.minecraft.world.phys.Vec3;
import org.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 xMouseSmoother = new SmoothDouble();
@Unique SmoothDouble yMouseSmoother = new SmoothDouble();
@Unique SmoothDouble pitchSmoother = new SmoothDouble();
@Unique SmoothDouble rollSmoother = new SmoothDouble();
@Unique SmoothDouble yawSmoother = new SmoothDouble();
@Shadow @Final private SmoothDouble smoothTurnY;
@Shadow @Final private SmoothDouble smoothTurnX;
@@ -41,6 +49,8 @@ public class MouseHandlerMixin {
@Shadow private double accumulatedDY;
@Shadow private double accumulatedScrollX;
@Inject(
method = "onScroll",
at = @At(
@@ -92,8 +102,13 @@ public class MouseHandlerMixin {
target = "Lnet/minecraft/client/player/LocalPlayer;turn(DD)V"
)
)
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.
public boolean cobblemon$modifyRotation(
LocalPlayer player,
double cursorDeltaX,
double cursorDeltaY,
@Local(argsOnly = true) double d,
@Local(argsOnly = true) double movementTime
) {
PokedexUsageContext usageContext = CobblemonClient.INSTANCE.getPokedexUsageContext();
if (usageContext.getScanningGuiOpen()) {
this.smoothTurnY.reset();
@@ -105,7 +120,80 @@ 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()) {
xMouseSmoother.reset();
yMouseSmoother.reset();
pitchSmoother.reset();
rollSmoother.reset();
yawSmoother.reset();
return true;
}
var defaultSensitivity = this.minecraft.options.sensitivity().get() * 0.6000000238418579 + 0.20000000298023224;
var ridingSensitivity = Math.pow(defaultSensitivity, 3);
//Send mouse input to be interpreted into rotation
//deltas by the ride controller
Vec3 angVecMouse = rollable.rotationOnMouseXY(
cursorDeltaY,
cursorDeltaX ,
yMouseSmoother,
xMouseSmoother,
ridingSensitivity,
movementTime
);
//Perform Rotation using mouse influenced rotation deltas.
rollable.rotate(
(float) angVecMouse.x,
(float) angVecMouse.y,
(float) angVecMouse.z
);
//Gather and apply the current rotation deltas
var angRot = rollable.angRollVel(movementTime);
//Apply smoothing if requested by the controller.
//This Might be best if done by the controller itself?
if( rollable.useAngVelSmoothing() )
{
if( angRot != null ) {
var yaw = yawSmoother.getNewDeltaValue(angRot.x * 0.5f, d);
var pitch = pitchSmoother.getNewDeltaValue(angRot.y * 0.5f, d);
var roll = rollSmoother.getNewDeltaValue(angRot.z * 0.5f, d);
rollable.rotate((float) yaw, (float) pitch, (float) roll);
}
}
//Otherwise simply apply the smoothing
else
{
if( angRot != null ) {
rollable.rotate((float) (
angRot.x * 10 * d),
(float) (angRot.y * 10 * d),
(float) (angRot.z * 10 * d)
);
}
}
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);
}
}
@@ -0,0 +1,36 @@
/*
* 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.api.riding.Rideable;
import com.cobblemon.mod.common.api.riding.RidingManager;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import net.minecraft.client.model.PlayerModel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(PlayerModel.class)
public class PlayerModelMixin {
@Inject(method = "setupAnim(Lnet/minecraft/world/entity/LivingEntity;FFFFF)V", at = @At(value = "HEAD"))
private void cobblemon$setHeadRotation(LivingEntity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch, CallbackInfo ci){
if (!(entity instanceof Player)) return;
Entity vehicle = entity.getVehicle();
if (!(vehicle instanceof PokemonEntity)) return;
RidingManager ridingManager = ((Rideable) vehicle).getRiding();
if (ridingManager.shouldRotatePlayerHead((PokemonEntity) vehicle)) return;
netHeadYaw = 0f;
headPitch = 0f;
}
}
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.client.render.ClientPlayerIcon;
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.MultiBufferSource;
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(PlayerRenderer.class)
public class PlayerRendererMixin {
@Inject(method = "render(Lnet/minecraft/world/entity/LivingEntity;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", at = @At(value = "TAIL"))
public void cobblemon$clientPlayerIcon(LivingEntity entity, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource buffer, int packedLight, CallbackInfo ci) {
ClientPlayerIcon.Companion.onRenderPlayer((Player) entity);
}
@Inject(
method = "setupRotations(Lnet/minecraft/client/player/AbstractClientPlayer;Lcom/mojang/blaze3d/vertex/PoseStack;FFFF)V",
at = @At("HEAD")
)
private void cobblemon$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, a, b, partialTicks, i);
}
}
}
}
@@ -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,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;
}
}
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.api.drop.ItemDropEntry
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.CobblemonEvents.DATA_SYNCHRONIZED
import com.cobblemon.mod.common.api.interaction.RequestManager
import com.cobblemon.mod.common.api.molang.ObjectValue
import com.cobblemon.mod.common.api.permission.PermissionValidator
import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalculator
import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalculators
@@ -62,7 +63,11 @@ import com.cobblemon.mod.common.api.storage.player.adapter.PlayerDataMongoBacken
import com.cobblemon.mod.common.api.storage.player.factory.CachedPlayerDataStoreFactory
import com.cobblemon.mod.common.api.tags.CobblemonEntityTypeTags
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import com.cobblemon.mod.common.battles.*
import com.cobblemon.mod.common.battles.BagItems
import com.cobblemon.mod.common.battles.BattleFormat
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.battles.BattleSide
import com.cobblemon.mod.common.battles.ShowdownThread
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.client.CobblemonPack
@@ -80,16 +85,29 @@ import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacke
import com.cobblemon.mod.common.permission.LaxPermissionValidator
import com.cobblemon.mod.common.platform.events.PlatformEvents
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.aspects.COSMETIC_SLOT_ASPECT
import com.cobblemon.mod.common.pokemon.aspects.GENDER_ASPECT
import com.cobblemon.mod.common.pokemon.aspects.SHINY_ASPECT
import com.cobblemon.mod.common.pokemon.evolution.variants.BlockClickEvolution
import com.cobblemon.mod.common.pokemon.feature.TagSeasonResolver
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
import com.cobblemon.mod.common.pokemon.properties.*
import com.cobblemon.mod.common.pokemon.properties.AspectPropertyType
import com.cobblemon.mod.common.pokemon.properties.BattleCloneProperty
import com.cobblemon.mod.common.pokemon.properties.FreezeFrameProperty
import com.cobblemon.mod.common.pokemon.properties.HiddenAbilityPropertyType
import com.cobblemon.mod.common.pokemon.properties.NoAIProperty
import com.cobblemon.mod.common.pokemon.properties.UnaspectPropertyType
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
import com.cobblemon.mod.common.pokemon.properties.tags.PokemonFlagProperty
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
import com.cobblemon.mod.common.util.*
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.ifDedicatedServer
import com.cobblemon.mod.common.util.isLaterVersion
import com.cobblemon.mod.common.util.party
import com.cobblemon.mod.common.util.requestWallpapers
import com.cobblemon.mod.common.util.server
import com.cobblemon.mod.common.world.feature.CobblemonPlacedFeatures
import com.cobblemon.mod.common.world.feature.ore.CobblemonOrePlacedFeatures
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
@@ -97,27 +115,29 @@ import com.mongodb.ConnectionString
import com.mongodb.MongoClientSettings
import com.mongodb.client.MongoClient
import com.mongodb.client.MongoClients
import java.io.File
import java.io.FileReader
import java.io.FileWriter
import java.io.PrintWriter
import java.util.UUID
import java.util.concurrent.TimeUnit
import kotlin.math.roundToInt
import kotlin.properties.Delegates
import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.isAccessible
import kotlin.reflect.jvm.javaField
import net.minecraft.client.Minecraft
import net.minecraft.commands.synchronization.SingletonArgumentInfo
import net.minecraft.resources.ResourceKey
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.NameTagItem
import net.minecraft.world.level.Level
import net.minecraft.world.level.storage.LevelResource
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger
import java.io.File
import java.io.FileReader
import java.io.FileWriter
import java.io.PrintWriter
import java.util.*
import kotlin.math.roundToInt
import kotlin.properties.Delegates
import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.isAccessible
import kotlin.reflect.jvm.javaField
object Cobblemon {
const val MODID = CobblemonBuildDetails.MOD_ID
@@ -151,7 +171,9 @@ object Cobblemon {
var permissionValidator: PermissionValidator by Delegates.observable(LaxPermissionValidator().also { it.initialize() }) { _, _, newValue -> newValue.initialize() }
var statProvider: StatProvider = CobblemonStatProvider
var seasonResolver: SeasonResolver = TagSeasonResolver
var wallpapers = mapOf<UUID, List<ResourceLocation>>()
var wallpapers = mutableMapOf<UUID, Set<ResourceLocation>>()
val serverPlayerStructs = mutableMapOf<UUID, ObjectValue<Player>>()
@JvmStatic
val builtinPacks = listOf<CobblemonPack>(
@@ -217,6 +239,7 @@ object Cobblemon {
storage.onPlayerDisconnect(it.player)
playerDataManager.onPlayerDisconnect(it.player)
RequestManager.onLogoff(it.player)
serverPlayerStructs.remove(it.player.uuid)
}
PlatformEvents.PLAYER_DEATH.subscribe {
PCLinkManager.removeLink(it.player.uuid)
@@ -278,6 +301,7 @@ object Cobblemon {
SHINY_ASPECT.register()
GENDER_ASPECT.register()
COSMETIC_SLOT_ASPECT.register()
SpeciesFeatures.types["choice"] = ChoiceSpeciesFeatureProvider::class.java
SpeciesFeatures.types["flag"] = FlagSpeciesFeatureProvider::class.java
@@ -385,9 +409,11 @@ object Cobblemon {
PlatformEvents.SERVER_STOPPED.subscribe {
storage.unregisterAll(it.server.registryAccess())
playerDataManager.saveAllStores()
playerDataManager.saveExecutor.shutdown()
playerDataManager.saveExecutor.awaitTermination(30L, TimeUnit.SECONDS)
}
PlatformEvents.SERVER_STARTED.subscribe {
bestSpawner.onServerStarted()
PlatformEvents.SERVER_STARTED.subscribe { event ->
bestSpawner.onServerStarted(event.server)
battleRegistry.onServerStarted()
}
PlatformEvents.SERVER_TICK_POST.subscribe { ServerTickHandler.onTick(it.server) }
@@ -535,6 +561,7 @@ object Cobblemon {
this.implementation.registerCommandArgument(cobblemonResource("form"), FormArgumentType::class, SingletonArgumentInfo.contextFree(FormArgumentType::form))
this.implementation.registerCommandArgument(cobblemonResource("dex"), DexArgumentType::class, SingletonArgumentInfo.contextFree (DexArgumentType::dex))
this.implementation.registerCommandArgument(cobblemonResource("npc_class"), NPCClassArgumentType::class, SingletonArgumentInfo.contextFree(NPCClassArgumentType::npcClass))
this.implementation.registerCommandArgument(cobblemonResource("wallpaper"), UnlockablePCBoxWallpaperArgumentType::class, SingletonArgumentInfo.contextFree(UnlockablePCBoxWallpaperArgumentType::wallpaper))
}
}
@@ -61,9 +61,11 @@ object CobblemonCommands {
ChangeBoxWallpaperCommand.register(dispatcher)
RunMolangScriptCommand.register(dispatcher)
CobblemonConfigCommand.register(dispatcher)
UnlockPCBoxWallpaperCommand.register(dispatcher)
// Possibly lock down registration if and only if under dev environment or running in an environment
// with a certain system environment variable set
CobblemonInfoCommand.register(dispatcher)
CalculateSeatPositionCommand.register(dispatcher)
}
}
@@ -0,0 +1,63 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.CosmeticItemAssignmentSyncPacket
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.cosmetic.CosmeticItemAssignment
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.ItemLikeConditionAdapter
import com.cobblemon.mod.common.util.adapters.PokemonPropertiesAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import net.minecraft.core.RegistryAccess
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
object CobblemonCosmeticItems : JsonDataRegistry<CosmeticItemAssignment> {
override val id = cobblemonResource("cosmetic_items")
override val type = PackType.SERVER_DATA
override val observable = SimpleObservable<CobblemonCosmeticItems>()
override val typeToken = TypeToken.get(CosmeticItemAssignment::class.java)
override val resourcePath = "cosmetic_items"
override val gson = GsonBuilder()
.setPrettyPrinting()
.registerTypeAdapter(PokemonProperties::class.java, PokemonPropertiesAdapter(saveLong = false))
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Item::class.java).type, ItemLikeConditionAdapter)
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.create()
val cosmeticItems = mutableListOf<CosmeticItemAssignment>()
override fun reload(data: Map<ResourceLocation, CosmeticItemAssignment>) {
cosmeticItems.clear()
data.entries.forEach { (id, value) -> value.id = id }
cosmeticItems.addAll(data.values)
}
override fun sync(player: ServerPlayer) {
CosmeticItemAssignmentSyncPacket(cosmeticItems).sendToPlayer(player)
}
fun findValidForPokemon(pokemon: Pokemon) = cosmeticItems.filter { it.pokemon.any { it.matches(pokemon) } }
fun findValidCosmeticForPokemonAndItem(registryAccess: RegistryAccess, pokemon: Pokemon, itemStack: ItemStack) = cosmeticItems
.filter { it.pokemon.any { it.matches(pokemon) } }
.flatMap { it.cosmeticItems }
.firstOrNull { it.consumedItem.fits(itemStack.item, registryAccess.registryOrThrow(Registries.ITEM)) }
}
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.MoParams
import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.data.DataRegistry
@@ -86,13 +87,23 @@ object CobblemonFlows : DataRegistry {
observable.emit(this)
}
fun run(eventResourceLocation: ResourceLocation, context: Map<String, MoValue>, cancelable: Cancelable? = null) {
fun run(
eventResourceLocation: ResourceLocation,
context: Map<String, MoValue>,
functions: Map<String, (MoParams) -> Any> = emptyMap(),
cancelable: Cancelable? = null
) {
if (cancelable == null) {
runtime.environment.query.functions.remove("cancel")
} else {
runtime.environment.query.addFunction("cancel") { cancelable }
}
// Most places in the mod use query structs so it's probably nicer to present the things as query values.
context.forEach { (key, value) -> runtime.environment.query.addFunction(key) { return@addFunction value } }
functions.forEach { (name, function) -> runtime.environment.query.addFunction(name, function) }
flows[eventResourceLocation]?.forEach {
if (cancelable != null && cancelable.isCanceled) {
return
@@ -1278,6 +1278,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
CobblemonHeldItemManager.registerRemap(it, remappedName)
CobblemonHeldItemManager.registerRemap(Items.BONE, "thickclub")
CobblemonHeldItemManager.registerRemap(Items.SNOWBALL, "snowball")
CobblemonHeldItemManager.registerRemap(Items.GOLD_BLOCK, "bignugget")
}
}
)
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.client.net.CalculateSeatPositionsHandler
import com.cobblemon.mod.common.client.net.PlayerInteractOptionsHandler
import com.cobblemon.mod.common.client.net.SetClientPlayerDataHandler
import com.cobblemon.mod.common.client.net.animation.PlayPosableAnimationHandler
@@ -47,8 +48,16 @@ import com.cobblemon.mod.common.client.net.storage.party.SetPartyPokemonHandler
import com.cobblemon.mod.common.client.net.storage.party.SetPartyReferenceHandler
import com.cobblemon.mod.common.client.net.storage.pc.*
import com.cobblemon.mod.common.client.net.toast.ToastPacketHandler
import com.cobblemon.mod.common.client.net.trade.*
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.CalculateSeatPositionsPacket
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
import com.cobblemon.mod.common.net.messages.client.SetClientPlayerDataPacket
import com.cobblemon.mod.common.net.messages.client.animation.PlayPosableAnimationPacket
@@ -87,17 +96,42 @@ 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.RenamePCBoxPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCBoxPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.ChangePCBoxWallpaperPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.RequestPCBoxWallpapersPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.SetPCBoxWallpapersPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.UnlockPCBoxWallpaperPacket
import com.cobblemon.mod.common.net.messages.client.toast.ToastPacket
import com.cobblemon.mod.common.net.messages.client.trade.*
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
@@ -108,6 +142,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
@@ -122,19 +157,22 @@ import com.cobblemon.mod.common.net.messages.server.storage.SwapPCPartyPokemonPa
import com.cobblemon.mod.common.net.messages.server.storage.party.MovePartyPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.party.ReleasePartyPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.party.SwapPartyPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.MovePCPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.MovePCPokemonToPartyPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.MovePartyPokemonToPCPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.PCBoxWallpapersPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.ReleasePCPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.RequestChangePCBoxWallpaperPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.RequestRenamePCBoxPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.SortPCBoxPacket
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.storage.pc.*
import com.cobblemon.mod.common.net.messages.server.trade.AcceptTradeRequestPacket
import com.cobblemon.mod.common.net.messages.server.trade.CancelTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.ChangeTradeAcceptancePacket
import com.cobblemon.mod.common.net.messages.server.trade.OfferTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.PerformTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.UpdateTradeOfferPacket
import com.cobblemon.mod.common.net.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
@@ -146,6 +184,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
@@ -164,7 +203,12 @@ import com.cobblemon.mod.common.net.serverhandling.storage.party.MovePartyPokemo
import com.cobblemon.mod.common.net.serverhandling.storage.party.ReleasePCPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.party.SwapPartyPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.pc.*
import com.cobblemon.mod.common.net.serverhandling.trade.*
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
@@ -177,13 +221,11 @@ import net.minecraft.server.level.ServerPlayer
* @since November 27th, 2021
*/
object CobblemonNetwork {
//private val logger = LogUtils.getLogger()
fun ServerPlayer.sendPacket(packet: NetworkPacket<*>) {
sendPacketToPlayer(this, packet)
}
fun sendToServer(packet: NetworkPacket<*>) {
//logger.info("[C->S] ${packet.type()}")
Cobblemon.implementation.networkManager.sendToServer(packet)
}
fun sendToAllPlayers(packet: NetworkPacket<*>) = sendPacketToPlayers(server()!!.playerList.players, packet)
@@ -222,6 +264,7 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(TeraTypeUpdatePacket.ID, TeraTypeUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(DmaxLevelUpdatePacket.ID, DmaxLevelUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(GmaxFactorUpdatePacket.ID, GmaxFactorUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(CosmeticItemUpdatePacket.ID, CosmeticItemUpdatePacket::decode, PokemonUpdatePacketHandler()))
// Evolution start
list.add(PacketRegisterInfo(AddEvolutionPacket.ID, AddEvolutionPacket::decode, PokemonUpdatePacketHandler()))
@@ -247,6 +290,7 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(RequestPCBoxWallpapersPacket.ID, RequestPCBoxWallpapersPacket::decode, RequestPCBoxWallpapersHandler))
list.add(PacketRegisterInfo(SetPCBoxWallpapersPacket.ID, SetPCBoxWallpapersPacket::decode, SetPCBoxWallpapersHandler))
list.add(PacketRegisterInfo(ChangePCBoxWallpaperPacket.ID, ChangePCBoxWallpaperPacket::decode, ChangePCBoxWallpaperHandler))
list.add(PacketRegisterInfo(UnlockPCBoxWallpaperPacket.ID, UnlockPCBoxWallpaperPacket::decode, UnlockPCBoxWallpaperHandler))
// UI Packets
list.add(PacketRegisterInfo(SummaryUIPacket.ID, SummaryUIPacket::decode, SummaryUIPacketHandler))
@@ -312,6 +356,7 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(DexEntrySyncPacket.ID, DexEntrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(FishingBaitRegistrySyncPacket.ID, FishingBaitRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(FlowRegistrySyncPacket.ID, FlowRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(CosmeticItemAssignmentSyncPacket.ID, CosmeticItemAssignmentSyncPacket::decode, DataRegistrySyncPacketHandler()))
// Effects
list.add(PacketRegisterInfo(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler))
@@ -364,6 +409,10 @@ object CobblemonNetwork {
// Pokédex scanning
list.add(PacketRegisterInfo(ServerConfirmedRegisterPacket.ID, ServerConfirmedRegisterPacket::decode, ServerConfirmedRegisterHandler))
// Debug / cheats
list.add(PacketRegisterInfo(CalculateSeatPositionsPacket.ID, CalculateSeatPositionsPacket::decode, CalculateSeatPositionsHandler))
return list
}
@@ -399,6 +448,7 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(RequestRenamePCBoxPacket.Companion.ID, RequestRenamePCBoxPacket.Companion::decode, RequestRenamePCBoxHandler))
list.add(PacketRegisterInfo(PCBoxWallpapersPacket.ID, PCBoxWallpapersPacket::decode, PCBoxWallpapersHandler))
list.add(PacketRegisterInfo(RequestChangePCBoxWallpaperPacket.ID, RequestChangePCBoxWallpaperPacket::decode, RequestChangePCBoxWallpaperHandler))
list.add(PacketRegisterInfo(MarkPCBoxWallpapersSeenPacket.ID, MarkPCBoxWallpapersSeenPacket::decode, MarkPCBoxWallpapersSeenHandler))
// Starter packets
list.add(PacketRegisterInfo(SelectStarterPacket.ID, SelectStarterPacket::decode, SelectStarterPacketHandler))
@@ -458,11 +508,13 @@ 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
}
fun sendPacketToPlayer(player: ServerPlayer, packet: NetworkPacket<*>) {
//logger.info("[S->C] ${packet.type()}")
Cobblemon.implementation.networkManager.sendPacketToPlayer(player, packet)
}
}
}
@@ -40,6 +40,8 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
val PC_RELEASE = this.create("pc.release")
@JvmField
val PC_CLICK = this.create("pc.click")
@JvmField
val PC_WALLPAPER_UNLOCK = this.create("pc.wallpaper.unlock")
@JvmField
val VILLAGER_WORK_NURSE = this.create("entity.villager.work_nurse")
@@ -0,0 +1,63 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.api.storage.pc.UnlockablePCWallpaper
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.TextAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
/**
* A data registry for unlockable wallpapers that can be applied to a PC box. This is different to a resource packed
* wallpaper, as those are purely client-side and don't require any unlocking.
*
* See docs/pc_wallpapers.md
*
* @author Hiroku
* @since February 9th, 2025
*/
object CobblemonUnlockableWallpapers : JsonDataRegistry<UnlockablePCWallpaper> {
override val gson: Gson = GsonBuilder()
.setPrettyPrinting()
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.registerTypeAdapter(Component::class.java, TextAdapter)
.create()
override val typeToken = TypeToken.get(UnlockablePCWallpaper::class.java)
override val resourcePath = "unlockable_pc_box_wallpapers"
override val id: ResourceLocation = cobblemonResource("unlockable_pc_box_wallpapers")
override val type = PackType.SERVER_DATA
override val observable = SimpleObservable<CobblemonUnlockableWallpapers>()
val unlockableWallpapers = mutableMapOf<ResourceLocation, UnlockablePCWallpaper>()
override fun sync(player: ServerPlayer) { /* These don't sync, they're applied to a PC instance from which they're hooked into RequestChangePCBoxWallpaperHandler. */ }
override fun reload(data: Map<ResourceLocation, UnlockablePCWallpaper>) {
unlockableWallpapers.clear()
data.forEach { (id, value) -> value.id = id }
unlockableWallpapers.putAll(data)
observable.emit(this)
}
}
@@ -28,7 +28,7 @@ class BattleCountableCriterion(
val CODEC: Codec<BattleCountableCriterion> = RecordCodecBuilder.create { it.group(
ContextAwarePredicate.CODEC.optionalFieldOf("player").forGetter(BattleCountableCriterion::playerCtx),
Codec.STRING.listOf().optionalFieldOf("battle_types", listOf("any")).forGetter(BattleCountableCriterion::battleTypes),
Codec.INT.optionalFieldOf( "count", 0).forGetter(BattleCountableCriterion::count)
Codec.INT.optionalFieldOf("count", 0).forGetter(BattleCountableCriterion::count)
).apply(it, ::BattleCountableCriterion) }
}
@@ -33,7 +33,7 @@ class LevelUpCriterion(
}
override fun matches(player: ServerPlayer, context: LevelUpContext): Boolean {
val preEvo = context.pokemon.preEvolution == null
val preEvo = context.pokemon.preEvolution != null
val hasEvolution = !context.pokemon.evolutions.none()
var evolutionCheck = true
if (preEvo || hasEvolution) {
@@ -43,27 +43,3 @@ class LevelUpCriterion(
}
}
/*class LevelUpCriterionCondition(id: Identifier, entity: LootContextPredicate) : SimpleCriterionCondition<LevelUpContext>(id, entity) {
var level = 0
var evolved = true
override fun toJson(json: JsonObject) {
json.addProperty("level", level)
json.addProperty("has_evolved", evolved)
}
override fun fromJson(json: JsonObject) {
level = json.get("level")?.asInt ?: 0
evolved = json.get("has_evolved")?.asBoolean ?: true
}
override fun matches(player: ServerPlayer, context: LevelUpContext): Boolean {
val preEvo = context.pokemon.preEvolution == null
val hasEvolution = !context.pokemon.evolutions.none()
var evolutionCheck = true
if (preEvo || hasEvolution) {
evolutionCheck = !(preEvo == hasEvolution)
}
return level == context.level && evolutionCheck == evolved
}
}*/
@@ -8,6 +8,9 @@
package com.cobblemon.mod.common.api.battles.interpreter
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.queryStructOf
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
/**
@@ -30,6 +33,13 @@ interface BattleContext {
/** The [BattlePokemon] that directly or indirectly caused this [BattleContext]. */
val origin: BattlePokemon?
fun getStruct() = queryStructOf(
"type" to { StringValue(type.name) },
"origin" to { origin?.struct ?: DoubleValue(0.0) },
"id" to { StringValue(id) },
"turn_created" to { DoubleValue(turn.toDouble()) }
)
/**
* The type of [BattleContext].
*
@@ -99,7 +99,6 @@ class Berry(
val weight: Float,
val boneMealChance: Float
) {
@Transient
var identifier: ResourceLocation = identifier
internal set
@@ -159,7 +158,7 @@ class Berry(
* Calculates the yield for a berry tree being planted or replanted after a life cycle.
* Triggers [BerryYieldCalculationEvent].
*
* @param world The [World] the tree is present in.
* @param world The [Level] the tree is present in.
* @param state The [BlockState] of the tree.
* @param pos The [BlockPos] of the tree.
* @param placer The [LivingEntity] tending to the tree, if any.
@@ -173,9 +172,10 @@ class Berry(
if (BerryBlock.getMulch(treeEntity) == MulchVariant.RICH) {
//I hope the upper bound isnt exclusive, especially when there's a method called nextBetweenExclusive
// update: it was meant to be exclusive, which caused #1124. I've lowered the upper bound from 3 to 2.
yield += world.random.nextIntBetweenInclusive(1, 2)
yield += world.random.nextIntBetweenInclusive(RICH_MULCH_MIN, RICH_MULCH_MAX)
treeEntity.decrementMulchDuration(world, pos, state)
}
yield = yield.coerceAtMost(growthPoints.size)
val event = BerryYieldCalculationEvent(this, world, state, pos, placer, yield, bonus.second)
CobblemonEvents.BERRY_YIELD.post(event) { yield = it.yield }
return yield
@@ -193,7 +193,7 @@ class Berry(
*
* @return The maximum possible yield.
*/
fun maxYield() = this.baseYield.last + this.growthFactors.sumOf { it.maxYield() }
fun maxYield() = this.baseYield.last + this.growthFactors.sumOf { it.maxYield() } + RICH_MULCH_MAX
/**
* Checks if this berry can mutate with the given [partner].
@@ -231,6 +231,7 @@ class Berry(
}
// A cheat since gson doesn't invoke init block
// well I actually suspect it does but
internal fun validate() {
if (this.baseYield.first < 0 || this.baseYield.last < 0) {
throw IllegalArgumentException("A berry base yield must be a positive range")
@@ -247,10 +248,6 @@ class Berry(
}
*/
this.growthFactors.forEach { it.validateArguments() }
val maxYield = this.maxYield()
if (this.growthPoints.size < maxYield) {
throw IllegalArgumentException("Anchor points must have enough elements for the max possible yield of $maxYield you've provided ${this.growthPoints.size} points")
}
this.shapedFlower = hashMapOf()
this.shapedFruit = hashMapOf()
this.sproutShape = this.createAndUniteShapes(this.sproutShapeBoxes)
@@ -339,6 +336,8 @@ class Berry(
}
companion object {
const val RICH_MULCH_MIN = 1
const val RICH_MULCH_MAX = 2
internal fun decode(buffer: RegistryFriendlyByteBuf): Berry {
val identifier = buffer.readIdentifier()
@@ -15,12 +15,10 @@ package com.cobblemon.mod.common.api.berry
* @author Licious
* @since November 28th, 2022
*/
enum class Flavor {
SPICY,
DRY,
SWEET,
BITTER,
SOUR
enum class Flavor(val colour: Int) {
SPICY(0x00FF00),
DRY(0xFF0000),
SWEET(0x0000FF),
BITTER(0xFFFF00),
SOUR(0xFF00FF);
}
@@ -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.api.conditional
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.codec.CodecUtils
import com.mojang.serialization.Codec
import net.minecraft.core.Registry
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceKey
import net.minecraft.tags.TagKey
val ITEM_REGISTRY_LIKE_CODEC = makeCodecForRegistryLikeCondition("item", Registries.ITEM)
fun <T : Any> makeCodecForRegistryLikeCondition(name: String, registryKey: ResourceKey<Registry<T>>): Codec<RegistryLikeCondition<T>> {
return CodecUtils.createByStringCodec(
from = { str ->
if (str.startsWith("#")) {
return@createByStringCodec RegistryLikeTagCondition<T>(TagKey.create(registryKey, str.substring(1).asIdentifierDefaultingNamespace()))
} else {
return@createByStringCodec RegistryLikeIdentifierCondition<T>(str.asIdentifierDefaultingNamespace())
}
},
to = { condition ->
if (condition is RegistryLikeTagCondition) {
"#${condition.tag.location}"
} else {
(condition as RegistryLikeIdentifierCondition).identifier.toString()
}
},
errorSupplier = { "Unknown $name condition: $it. Should be # followed by a tag, or $name resource location e.g. #minecraft:ladders or minecraft:grass_block." }
)
}
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.api.conditional
import net.minecraft.core.Holder
import net.minecraft.core.Registry
/**
@@ -17,5 +18,10 @@ import net.minecraft.core.Registry
* @since July 16th, 2022
*/
interface RegistryLikeCondition<T> {
fun fits(t: T, registry: Registry<T>): Boolean
fun fits(t: T, registry: Registry<T>): Boolean {
val holder = registry.wrapAsHolder(t)
return holder != null && fits(holder)
}
fun fits(holder: Holder<T>): Boolean
}
@@ -9,7 +9,7 @@
package com.cobblemon.mod.common.api.conditional
import com.google.gson.JsonElement
import net.minecraft.core.Registry
import net.minecraft.core.Holder
import net.minecraft.resources.ResourceLocation
/**
@@ -24,5 +24,6 @@ open class RegistryLikeIdentifierCondition<T : Any>(val identifier: ResourceLoca
constructor: (ResourceLocation) -> RegistryLikeIdentifierCondition<T>
): (JsonElement) -> RegistryLikeIdentifierCondition<T>? = { constructor(ResourceLocation.parse(it.asString)) }
}
override fun fits(t: T, registry: Registry<T>) = registry.getKey(t) == identifier
override fun fits(t: Holder<T>) = t.`is`(identifier)
}
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.api.conditional
import com.google.gson.JsonElement
import net.minecraft.core.Holder
import net.minecraft.core.Registry
import net.minecraft.resources.ResourceKey
import net.minecraft.resources.ResourceLocation
@@ -26,29 +27,18 @@ open class RegistryLikeTagCondition<T : Any>(val tag: TagKey<T>) : RegistryLikeC
companion object {
const val PREFIX = "#"
fun <T : Any> resolver(
ResourceKey: ResourceKey<Registry<T>>,
resourceKey: ResourceKey<Registry<T>>,
constructor: (TagKey<T>) -> RegistryLikeTagCondition<T>
): (JsonElement) -> RegistryLikeTagCondition<T>? = {
val firstSymbol = it.asString.substring(0, 1)
if (firstSymbol == PREFIX) {
val identifier = ResourceLocation.parse(it.asString.substring(1))
constructor(TagKey.create(ResourceKey, identifier))
constructor(TagKey.create(resourceKey, identifier))
} else {
null
}
}
}
override fun fits(t: T, registry: Registry<T>): Boolean {
// val registryHasTag = registry.containsTag(tag)
// if (!registryHasTag) {
//// LOGGER.warn("No tag in registry: ${tag.id}")
// return false
// }
return registry.getResourceKey(t)
.flatMap(registry::getHolder)
.map { entry -> entry.`is`(tag) }
.orElse(false)
}
override fun fits(t: Holder<T>) = t.`is`(tag)
}
@@ -11,6 +11,8 @@ package com.cobblemon.mod.common.api.entity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.world.damagesource.DamageSource
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.Entity.MoveFunction
import net.minecraft.world.entity.player.Player
interface PokemonSideDelegate : EntitySideDelegate<PokemonEntity> {
@@ -8,6 +8,10 @@
package com.cobblemon.mod.common.api.events
import com.bedrockk.molang.runtime.MoParams
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.MoValue
/**
* Something that can be canceled. This is a highly complex class and should only be read by professional engineers.
*
@@ -21,4 +25,9 @@ abstract class Cancelable {
fun cancel() {
isCanceled = true
}
val cancelFunc: Pair<String, (MoParams) -> MoValue> = "cancel" to {
cancel()
DoubleValue.ONE
}
}
@@ -46,12 +46,14 @@ import com.cobblemon.mod.common.api.events.storage.ChangePCBoxWallpaperEvent
import com.cobblemon.mod.common.api.events.storage.ReleasePokemonEvent
import com.cobblemon.mod.common.api.events.storage.RenamePCBoxEvent
import com.cobblemon.mod.common.api.events.storage.WallpaperCollectionEvent
import com.cobblemon.mod.common.api.events.storage.WallpaperUnlockedEvent
import com.cobblemon.mod.common.api.events.world.BigRootPropagatedEvent
import com.cobblemon.mod.common.api.reactive.CancelableObservable
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
@@ -178,6 +180,8 @@ object CobblemonEvents {
@JvmField
val WALLPAPER_COLLECTION_EVENT = EventObservable<WallpaperCollectionEvent>()
@JvmField
val WALLPAPER_UNLOCKED_EVENT = CancelableObservable<WallpaperUnlockedEvent>()
@JvmField
val CHANGE_PC_BOX_WALLPAPER_EVENT_PRE = CancelableObservable<ChangePCBoxWallpaperEvent.Pre>()
@@ -211,6 +215,10 @@ object CobblemonEvents {
val HELD_ITEM_PRE = CancelableObservable<HeldItemEvent.Pre>()
@JvmField
val HELD_ITEM_POST = EventObservable<HeldItemEvent.Post>()
@JvmField
val COSMETIC_ITEM_PRE = CancelableObservable<HeldItemEvent.Pre>()
@JvmField
val COSMETIC_ITEM_POST = EventObservable<HeldItemEvent.Post>()
@JvmField
val POKEMON_GAINED = EventObservable<PokemonGainedEvent>()
@@ -253,4 +261,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>()
}
@@ -8,16 +8,12 @@
package com.cobblemon.mod.common.api.events.battles
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.MoValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.util.asArrayValue
import java.util.function.Function
/**
* Event fired when a [BattlePokemon] faints. Exposes the [BattlePokemon] that fainted and the [BattleContext]
@@ -37,13 +33,6 @@ data class BattleFaintedEvent(
"npcs" to battle.actors.filter { it.type == ActorType.NPC }.asArrayValue { it.struct },
"wild_pokemon" to battle.actors.filter { it.type == ActorType.WILD }.asArrayValue { it.struct },
"pokemon" to killed.struct,
"context" to QueryStruct(
hashMapOf(
"type" to Function { StringValue(context.type.name) },
"origin" to Function { context.origin?.struct ?: DoubleValue(0.0) },
"id" to Function { StringValue(context.id) },
"turn_created" to Function { DoubleValue(context.turn.toDouble()) },
)
)
"context" to context.getStruct()
)
}
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.api.events.battles
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.util.asArrayValue
import net.minecraft.network.chat.MutableComponent
@@ -30,6 +31,8 @@ data class BattleStartedPreEvent (override val battle: PokemonBattle, var reason
"npcs" to battle.actors.filter { it.type == ActorType.NPC }.asArrayValue { it.struct },
"wild_pokemon" to battle.actors.filter { it.type == ActorType.WILD }.asArrayValue { it.struct }
)
val functions = moLangFunctionMap(cancelFunc)
}
/**
@@ -26,7 +26,7 @@ data class TerastallizationEvent(
val battle: PokemonBattle,
val pokemon: BattlePokemon,
val teraType: TeraType
) {
) {
val context = mutableMapOf<String, MoValue>(
"battle" to battle.struct,
"players" to battle.actors.filter { it.type == ActorType.PLAYER }.asArrayValue { it.struct },
@@ -8,9 +8,15 @@
package com.cobblemon.mod.common.api.events.pokeball
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.api.pokeball.catching.CaptureContext
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.getBooleanOrNull
import com.cobblemon.mod.common.util.getIntOrNull
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.LivingEntity
@@ -32,4 +38,34 @@ class PokeBallCaptureCalculatedEvent(
action(this, thrower)
}
}
val context = mutableMapOf<String, MoValue>(
"thrower" to thrower.asMostSpecificMoLangValue(),
"pokemon" to pokemonEntity.struct,
"poke_ball" to pokeBallEntity.struct,
"is_successful_capture" to DoubleValue(captureResult.isSuccessfulCapture),
"is_critical_capture" to DoubleValue(captureResult.isCriticalCapture),
)
val functions = moLangFunctionMap(
"set_shakes" to { params ->
val numShakes = params.getInt(0)
val successful = params.getBooleanOrNull(1) ?: (numShakes == 4)
captureResult = CaptureContext(
numberOfShakes = numShakes,
isSuccessfulCapture = successful,
isCriticalCapture = false
)
DoubleValue.ONE
},
"set_critical_capture" to { params ->
val numShakes = params.getIntOrNull(0) ?: 1
captureResult = CaptureContext(
numberOfShakes = numShakes,
isSuccessfulCapture = true,
isCriticalCapture = true
)
DoubleValue.ONE
}
)
}
@@ -20,8 +20,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
data class FriendshipUpdatedEvent(
val pokemon: Pokemon,
val newFriendshipInitial: Int
)
{
) {
var newFriendship: Int = newFriendshipInitial
set(value) {
field = value.coerceIn(0, Cobblemon.config.maxPokemonFriendship)
@@ -9,13 +9,11 @@
package com.cobblemon.mod.common.api.events.pokemon
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.api.events.pokemon.HeldItemEvent.Post
import com.cobblemon.mod.common.api.events.pokemon.HeldItemEvent.Pre
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.world.item.ItemStack
/**
* The base for all the events related to held items.
* The base for all the events related to held items and cosmetic items.
*
* @see [Pre]
* @see [Post]
@@ -28,7 +26,7 @@ interface HeldItemEvent {
val pokemon: Pokemon
/**
* Fired at the start of [Pokemon.swapHeldItem].
* Fired at the start of [Pokemon.swapHeldItem] and [Pokemon.swapCosmeticItem].
*
* This event should be used to mutate the results of this transaction.
*
@@ -44,7 +42,7 @@ interface HeldItemEvent {
data class Pre(override val pokemon: Pokemon, var receiving: ItemStack, var returning: ItemStack, var decrement: Boolean) : HeldItemEvent, Cancelable()
/**
* Fired at the end of [Pokemon.swapHeldItem].
* Fired at the end of [Pokemon.swapHeldItem] and [Pokemon.swapCosmeticItem].
*
* @property pokemon The [Pokemon] triggering this event.
* @property received The [ItemStack] considered as received and set to the [pokemon]. This is a copy and mutation will not be taken into account.
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.api.events.pokemon
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.pokemon.Pokemon
/**
@@ -23,4 +24,11 @@ class LevelUpEvent(val pokemon: Pokemon, val oldLevel: Int, var newLevel: Int) {
"old_level" to DoubleValue(oldLevel.toDouble()),
"new_level" to DoubleValue(newLevel.toDouble())
)
val functions = moLangFunctionMap(
"set_new_level" to {
newLevel = it.getInt(0)
DoubleValue.ONE
}
)
}
@@ -13,6 +13,7 @@ import com.bedrockk.molang.runtime.value.MoValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.api.pokedex.AbstractPokedexManager
import com.cobblemon.mod.common.api.pokedex.FormDexRecord
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
@@ -47,7 +48,9 @@ sealed interface PokedexDataChangedEvent {
override val knowledge: PokedexEntryProgress,
override val playerUUID: UUID,
override val record: FormDexRecord
) : PokedexDataChangedEvent, Cancelable()
) : PokedexDataChangedEvent, Cancelable() {
val functions = moLangFunctionMap(cancelFunc)
}
class Post(
override val dataSource: PokedexEntityData,
@@ -8,8 +8,12 @@
package com.cobblemon.mod.common.api.events.pokemon
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.server
import java.util.UUID
data class PokemonGainedEvent(
@@ -20,4 +24,8 @@ data class PokemonGainedEvent(
"player_id" to StringValue(playerId.toString()),
"pokemon" to pokemon.struct
)
val functions = moLangFunctionMap(
"player" to { server()?.playerList?.getPlayer(playerId)?.asMoLangValue() ?: DoubleValue.ZERO },
)
}
@@ -8,7 +8,10 @@
package com.cobblemon.mod.common.api.events.pokemon.evolution
import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.pokemon.Pokemon
@@ -25,4 +28,11 @@ import com.cobblemon.mod.common.pokemon.Pokemon
data class EvolutionAcceptedEvent(
override val pokemon: Pokemon,
override val evolution: Evolution
) : Cancelable(), EvolutionEvent
) : Cancelable(), EvolutionEvent {
val context = mutableMapOf<String, MoValue>(
"pokemon" to pokemon.struct,
"evolution" to evolution.asMoLangValue()
)
val functions = moLangFunctionMap(cancelFunc)
}
@@ -8,6 +8,8 @@
package com.cobblemon.mod.common.api.events.pokemon.evolution
import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.pokemon.Pokemon
@@ -23,4 +25,9 @@ import com.cobblemon.mod.common.pokemon.Pokemon
data class EvolutionCompleteEvent(
override val pokemon: Pokemon,
override val evolution: Evolution
) : EvolutionEvent
) : EvolutionEvent {
val context = mutableMapOf<String, MoValue>(
"pokemon" to pokemon.struct,
"evolution" to evolution.asMoLangValue()
)
}
@@ -8,8 +8,13 @@
package com.cobblemon.mod.common.api.events.pokemon.evolution
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.getBoolean
/**
* An event fired when [Evolution.test] has been performed.
@@ -25,4 +30,18 @@ data class EvolutionTestedEvent(
override val evolution: Evolution,
val originalResult: Boolean,
var result: Boolean
) : EvolutionEvent
) : EvolutionEvent {
val context = mutableMapOf<String, MoValue>(
"pokemon" to pokemon.struct,
"evolution" to evolution.asMoLangValue(),
"original_result" to DoubleValue(originalResult),
)
val functions = moLangFunctionMap(
"result" to { DoubleValue(result) },
"set_result" to {
result = it.getBoolean(0)
DoubleValue.ONE
}
)
}
@@ -16,6 +16,9 @@ import java.util.UUID
data class PokemonInteractionGUICreationEvent(
val pokemonID: UUID,
val mountShoulder: Boolean,
val giveHeld: Boolean,
val giveCosmetic: Boolean,
val canRide: Boolean,
val options: Multimap<Orientation, InteractWheelOption>
) {
fun addFillingOption(option: InteractWheelOption) {
@@ -28,7 +31,7 @@ data class PokemonInteractionGUICreationEvent(
private fun getNextFreeOrientation(): Orientation {
var largest = Orientation.TOP_LEFT
for(orientation in Orientation.values()) {
for (orientation in Orientation.entries) {
if(!options.containsKey(orientation)) {
return orientation
} else {
@@ -22,5 +22,5 @@ import net.minecraft.server.level.ServerPlayer
*/
data class WallpaperCollectionEvent(
val player: ServerPlayer,
val wallpapers: MutableList<ResourceLocation>
val wallpapers: MutableSet<ResourceLocation>
)
@@ -0,0 +1,57 @@
/*
* 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.events.storage
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.api.storage.pc.PCStore
import com.cobblemon.mod.common.api.storage.pc.UnlockablePCWallpaper
import com.cobblemon.mod.common.util.asArrayValue
import com.cobblemon.mod.common.util.getBoolean
import net.minecraft.server.level.ServerPlayer
/**
* Event fired when a wallpaper is unlocked for a PC. Typically, this will have a single player, but it is not
* technically guaranteed to due to shared PCs and offline support.
*
* @author Hiroku
* @since February 10th, 2025
*/
data class WallpaperUnlockedEvent(
val pc: PCStore,
val wallpaper: UnlockablePCWallpaper,
var shouldNotify: Boolean
): Cancelable() {
/** For shared PCs with multiple players online, and for offline PC access, the player will be null. */
val player: ServerPlayer?
get() = pc.getObservingPlayers().takeIf { it.size == 1 }?.first()
/** All online, observing players for the PC. This would typically have a single player in it. */
val players = pc.getObservingPlayers()
val context: MutableMap<String, MoValue>
get() = mutableMapOf(
"pc" to pc.struct,
"wallpaper" to wallpaper.struct,
"player" to (player?.asMoLangValue() ?: DoubleValue.ZERO),
"players" to players.asArrayValue { it.asMoLangValue() },
"should_notify" to DoubleValue(shouldNotify)
)
val functions = moLangFunctionMap(
cancelFunc,
"set_should_notify" to { params ->
shouldNotify = params.getBoolean(0)
DoubleValue.ONE
}
)
}
@@ -37,6 +37,8 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.util.FormattedCharSequence
import org.joml.Matrix4f
import org.joml.Vector3f
import org.lwjgl.opengl.GL30
import java.nio.ByteBuffer
@JvmOverloads
fun blitk(
@@ -364,4 +366,26 @@ fun renderSprite(matrixStack: PoseStack, sprite: ResourceLocation) {
buffer.addVertex(matrix, 2f, 2f, 0.0f).setUv(1f, 1f)
BufferUploader.drawWithShader(buffer.buildOrThrow())
}
}
fun getPixelRGB(x: Int, y: Int): Triple<Int, Int, Int> {
val window = Minecraft.getInstance().window
val scale = window.guiScale
val buffer = ByteBuffer.allocateDirect(4)
RenderSystem.readPixels(
(x * scale).toInt(),
(window.height - y * scale - scale).toInt(),
1,
1,
GL30.GL_RGBA,
GL30.GL_UNSIGNED_BYTE,
buffer
)
return Triple(
buffer[0].toInt() and 0xFF,
buffer[1].toInt() and 0xFF,
buffer[2].toInt() and 0xFF
)
}
@@ -21,6 +21,7 @@ import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonActivities
import com.cobblemon.mod.common.CobblemonBlockEntities
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.CobblemonUnlockableWallpapers
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
@@ -36,7 +37,11 @@ import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.api.pokedex.PokedexManager
import com.cobblemon.mod.common.api.pokedex.SeenCount
import com.cobblemon.mod.common.api.pokedex.SeenPercent
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.riding.RidingStyle
import com.cobblemon.mod.common.api.riding.stats.RidingStat
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.storage.PokemonStore
@@ -60,8 +65,12 @@ import com.cobblemon.mod.common.net.messages.client.animation.PlayPosableAnimati
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
import com.cobblemon.mod.common.pokemon.Gender
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
import com.cobblemon.mod.common.pokemon.evolution.variants.LevelUpEvolution
import com.cobblemon.mod.common.pokemon.evolution.variants.TradeEvolution
import com.cobblemon.mod.common.util.*
import com.mojang.datafixers.util.Either
import java.util.UUID
@@ -71,6 +80,7 @@ import net.minecraft.commands.arguments.EntityAnchorArgument
import net.minecraft.core.BlockPos
import net.minecraft.core.Holder
import net.minecraft.core.Registry
import net.minecraft.core.RegistryAccess
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
import net.minecraft.nbt.CompoundTag
@@ -86,6 +96,7 @@ import net.minecraft.server.level.ServerPlayer
import net.minecraft.tags.TagKey
import net.minecraft.world.damagesource.DamageSource
import net.minecraft.world.damagesource.DamageTypes
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.EntityType
import net.minecraft.world.entity.LightningBolt
import net.minecraft.world.entity.LivingEntity
@@ -95,6 +106,7 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.memory.MemoryStatus
import net.minecraft.world.entity.ai.memory.WalkTarget
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level
import net.minecraft.world.level.Level.ExplosionInteraction
import net.minecraft.world.level.biome.Biome
@@ -300,6 +312,11 @@ object MoLangFunctions {
.map { it.asMostSpecificMoLangValue() }
.asArrayValue()
}
map.put("is_healer_in_use") { params ->
val pos = params.get<ArrayStruct>(0).asBlockPos()
val healer = world.getBlockEntity(pos, CobblemonBlockEntities.HEALING_MACHINE).orElse(null) ?: return@put DoubleValue.ONE
return@put DoubleValue(healer.isInUse)
}
return@mutableListOf map
}
@@ -311,8 +328,8 @@ object MoLangFunctions {
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
map.put("username") { _ -> StringValue(player.gameProfile.name) }
map.put("uuid") { _ -> StringValue(player.gameProfile.id.toString()) }
map.put("main_held_item") { _ -> player.level().itemRegistry.wrapAsHolder(player.mainHandItem.item).asMoLangValue(Registries.ITEM) }
map.put("off_held_item") { _ -> player.level().itemRegistry.wrapAsHolder(player.offhandItem.item).asMoLangValue(Registries.ITEM) }
map.put("main_held_item") { _ -> player.mainHandItem.asMoLangValue(player.registryAccess()) }
map.put("off_held_item") { _ -> player.offhandItem.asMoLangValue(player.registryAccess()) }
map.put("face") { params -> ObjectValue(PlayerDialogueFaceProvider(player.uuid, params.getBooleanOrNull(0) != false)) }
map.put("swing_hand") { _ -> player.swing(player.usedItemHand) }
map.put("food_level") { _ -> DoubleValue(player.foodData.foodLevel) }
@@ -406,11 +423,39 @@ object MoLangFunctions {
return@put DoubleValue.ONE
}
map.put("pokedex") { player.pokedex().struct }
map.put("has_advancement") { params ->
val requiredAdvancement = ResourceLocation.parse(params.getString(0))
for (entry in player.advancements.progress) {
if (entry.key.id == requiredAdvancement && entry.value.isDone) {
return@put DoubleValue.ONE
}
}
return@put DoubleValue.ZERO
}
}
map
}
)
val entityFunctions: MutableList<(LivingEntity) -> HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf<(LivingEntity) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
val itemStackFunctions = mutableListOf<(ItemStack, RegistryAccess) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
{ stack, registryAccess ->
val itemRegistry = registryAccess.registryOrThrow(Registries.ITEM)
val holder = itemRegistry.wrapAsHolder(stack.item)
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
map.put("item") { _ -> holder.asMoLangValue(Registries.ITEM) }
map.put("count") { _ -> DoubleValue(stack.count.toDouble()) }
map.put("damage_value") { _ -> DoubleValue(stack.damageValue) }
map.put("max_damage") { _ -> DoubleValue(stack.maxDamage) }
map.put("is_empty") { _ -> DoubleValue(stack.isEmpty) }
map.put("shrink") { params -> stack.shrink(params.getInt(0)) }
map.put("grow") { params -> stack.grow(params.getInt(0)) }
map.put("is_of") { params -> DoubleValue(holder.`is`(params.getString(0).asIdentifierDefaultingNamespace())) }
map.put("is_in") { params -> DoubleValue(holder.`is`(TagKey.create(Registries.ITEM, params.getString(0).replace("#", "").asIdentifierDefaultingNamespace()))) }
return@mutableListOf map
}
)
val entityFunctions: MutableList<(Entity) -> HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf(
{ entity ->
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
map.put("uuid") { _ -> StringValue(entity.uuid.toString()) }
@@ -419,31 +464,8 @@ object MoLangFunctions {
val source = DamageSource(entity.level().registryAccess().registryOrThrow(Registries.DAMAGE_TYPE).getHolder(DamageTypes.GENERIC).get())
entity.hurt(source, amount.toFloat())
}
map.put("walk_to") { params ->
val x = params.getDouble(0)
val y = params.getDouble(1)
val z = params.getDouble(2)
val speedMultiplier = params.getDoubleOrNull(3) ?: 0.35
if (entity is PathfinderMob) {
if (entity.brain.checkMemory(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED)) {
entity.brain.setMemory(MemoryModuleType.WALK_TARGET, WalkTarget(Vec3(x, y, z), speedMultiplier.toFloat(), 1))
entity.brain.setMemory(MemoryModuleType.LOOK_TARGET, BlockPosTracker(Vec3(x, y + entity.eyeHeight, z)))
} else {
entity.navigation.moveTo(x, y, z, speedMultiplier)
entity.lookControl.setLookAt(Vec3(x, y + entity.eyeHeight, z))
}
}
}
map.put("has_walk_target") { _ ->
if (entity is PathfinderMob) {
DoubleValue(entity.brain.getMemory(MemoryModuleType.WALK_TARGET).isPresent || entity.isPathFinding)
} else {
DoubleValue.ZERO
}
}
map.put("is_sneaking") { _ -> DoubleValue(entity.isShiftKeyDown) }
map.put("is_sprinting") { _ -> DoubleValue(entity.isSprinting) }
map.put("is_flying") { _ -> DoubleValue(entity.isFallFlying) }
map.put("is_in_water") { _ -> DoubleValue(entity.isUnderWater) }
map.put("is_touching_water_or_rain") { _ -> DoubleValue(entity.isInWaterRainOrBubble) }
map.put("is_touching_water") { _ -> DoubleValue(entity.isInWater) }
@@ -451,16 +473,13 @@ object MoLangFunctions {
map.put("is_in_lava") { _ -> DoubleValue(entity.isInLava) }
map.put("is_on_fire") { _ -> DoubleValue(entity.isOnFire) }
map.put("is_invisible") { _ -> DoubleValue(entity.isInvisible) }
map.put("is_sleeping") { _ -> DoubleValue(entity.isSleeping) }
map.put("is_riding") { _ -> DoubleValue(entity.isPassenger) }
map.put("health") { _ -> DoubleValue(entity.health) }
map.put("distance_to_pos") { params ->
val x = params.getDouble(0)
val y = params.getDouble(1)
val z = params.getDouble(2)
return@put DoubleValue(sqrt(entity.distanceToSqr(Vec3(x, y, z))))
}
map.put("max_health") { _ -> DoubleValue(entity.maxHealth) }
map.put("name") { _ -> StringValue(entity.effectiveName().string) }
map.put("type") { _ ->
entity.registryAccess().registry(Registries.ENTITY_TYPE).get().getKey(entity.type)?.toString()?.let {
@@ -487,11 +506,6 @@ object MoLangFunctions {
map.put("world") { _ -> entity.level().worldRegistry.wrapAsHolder(entity.level()).asWorldMoLangValue() }
map.put("biome") { _ -> entity.level().getBiome(entity.blockPosition()).asBiomeMoLangValue() }
map.put("is_passenger") { DoubleValue(entity.isPassenger) }
map.put("is_healer_in_use") { params ->
val pos = params.get<ArrayStruct>(0).asBlockPos()
val healer = entity.level().getBlockEntity(pos, CobblemonBlockEntities.HEALING_MACHINE).orElse(null) ?: return@put DoubleValue.ONE
return@put DoubleValue(healer.isInUse)
}
map.put("find_nearby_block") { params ->
val type = params.getString(0).asIdentifierDefaultingNamespace(namespace = "minecraft")
val isTag = type.path.startsWith("#")
@@ -510,7 +524,7 @@ object MoLangFunctions {
val distance = params.getDouble(0)
val entities = entity.level().getEntities(entity, AABB.ofSize(entity.position(), distance, distance, distance))
return@put entities
.filterIsInstance<LivingEntity>()
.filterIsInstance<Entity>()
.map { it.asMostSpecificMoLangValue() }
.asArrayValue()
}
@@ -567,6 +581,45 @@ object MoLangFunctions {
packet.sendToPlayer(player)
}
}
return@mutableListOf map
}
)
val livingEntityFunctions: MutableList<(LivingEntity) -> HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf<(LivingEntity) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
{ entity ->
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
map.put("is_living_entity") { DoubleValue.ONE }
map.put("is_flying") { _ -> DoubleValue(entity.isFallFlying) }
map.put("is_sleeping") { _ -> DoubleValue(entity.isSleeping) }
map.put("health") { _ -> DoubleValue(entity.health) }
map.put("max_health") { _ -> DoubleValue(entity.maxHealth) }
if (entity is PathfinderMob) {
map.put("walk_to") { params ->
val x = params.getDouble(0)
val y = params.getDouble(1)
val z = params.getDouble(2)
val speedMultiplier = params.getDoubleOrNull(3) ?: 0.35
if (entity.brain.checkMemory(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED)) {
entity.brain.setMemory(
MemoryModuleType.WALK_TARGET,
WalkTarget(Vec3(x, y, z), speedMultiplier.toFloat(), 1)
)
entity.brain.setMemory(
MemoryModuleType.LOOK_TARGET,
BlockPosTracker(Vec3(x, y + entity.eyeHeight, z))
)
} else {
entity.navigation.moveTo(x, y, z, speedMultiplier)
entity.lookControl.setLookAt(Vec3(x, y + entity.eyeHeight, z))
}
}
map.put("has_walk_target") { _ ->
DoubleValue(entity.brain.getMemory(MemoryModuleType.WALK_TARGET).isPresent || entity.isPathFinding)
}
}
map
}
)
@@ -735,6 +788,7 @@ object MoLangFunctions {
map.put("is_flying") { DoubleValue(pokemonEntity.getBehaviourFlag(PokemonBehaviourFlag.FLYING)) }
map.put("has_aspect") { DoubleValue(it.getString(0) in pokemonEntity.aspects) }
map.put("is_pokemon") { DoubleValue.ONE }
map.put("is_holding_item") { DoubleValue(!pokemonEntity.entityData.get(PokemonEntity.SHOWN_HELD_ITEM).isEmpty) }
map
}
)
@@ -742,6 +796,7 @@ object MoLangFunctions {
val pokemonStoreFunctions = mutableListOf<(PokemonStore<*>) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
{ store ->
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
map.put("uuid") { StringValue(store.uuid.toString()) }
map.put("add") { params ->
val pokemon = params.get<ObjectValue<Pokemon>>(0)
return@put DoubleValue(store.add(pokemon.obj))
@@ -842,6 +897,17 @@ object MoLangFunctions {
return@put DoubleValue.ONE
}
map.put("get_box_count") { _ -> DoubleValue(pc.boxes.size.toDouble()) }
map.put("has_unlocked_wallpaper") { params ->
val wallpaper = params.getString(0).asIdentifierDefaultingNamespace()
return@put DoubleValue(pc.unlockedWallpapers.contains(wallpaper))
}
map.put("get_unlocked_wallpapers") { pc.unlockedWallpapers.asArrayValue { StringValue(it.toString()) } }
map.put("unlock_wallpaper") {
val wallpaper = it.getString(0).asIdentifierDefaultingNamespace()
val playSound = it.getBooleanOrNull(1) != false
CobblemonUnlockableWallpapers.unlockableWallpapers[wallpaper] ?: return@put DoubleValue.ZERO
return@put DoubleValue(pc.unlockWallpaper(wallpaper, playSound))
}
return@mutableListOf map
}
)
@@ -850,7 +916,7 @@ object MoLangFunctions {
{ spawningContext ->
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
val worldValue = spawningContext.world.registryAccess().registryOrThrow(Registries.DIMENSION).wrapAsHolder(spawningContext.world).asWorldMoLangValue()
val biomeValue = spawningContext.biomeRegistry.wrapAsHolder(spawningContext.biome).asBiomeMoLangValue()
val biomeValue = spawningContext.biomeHolder.asBiomeMoLangValue()
map.put("biome") { _ -> biomeValue }
map.put("world") { _ -> worldValue }
map.put("light") { _ -> DoubleValue(spawningContext.light.toDouble()) }
@@ -1002,18 +1068,111 @@ object MoLangFunctions {
}
)
val pokemonPropertiesFunctions: MutableList<(PokemonProperties) -> HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf(
{ props ->
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
map.put("level") { DoubleValue(props.level?.toDouble() ?: 0) }
map.put("set_level") { params ->
props.level = params.getIntOrNull(0)
return@put DoubleValue.ONE
}
map.put("shiny") { DoubleValue(props.shiny) }
map.put("set_shiny") { params ->
props.shiny = params.getBooleanOrNull(0)
return@put DoubleValue.ONE
}
map.put("species") { props.species?.let { StringValue(it) } ?: DoubleValue.ZERO }
map.put("set_species") { params ->
props.species = params.getStringOrNull(0)
return@put DoubleValue.ONE
}
map.put("gender") { props.gender?.let { StringValue(it.name) } ?: DoubleValue.ZERO }
map.put("set_gender") { params ->
props.gender = params.getStringOrNull(0)?.let { Gender.valueOf(it) }
return@put DoubleValue.ONE
}
map.put("form") { props.form?.let { StringValue(it) } ?: DoubleValue.ZERO }
map.put("ivs") {
val ivs = props.ivs
if (ivs == null) {
return@put DoubleValue.ZERO
} else {
return@put ivs.struct
}
}
map.put("evs") {
val evs = props.evs
if (evs == null) {
return@put DoubleValue.ZERO
} else {
return@put evs.struct
}
}
map.put("friendship") { DoubleValue(props.friendship?.toDouble() ?: DoubleValue.ZERO) }
map.put("set_friendship") { params ->
props.friendship = params.getIntOrNull(0)
return@put DoubleValue.ONE
}
map.put("create") { params ->
val pokemon = props.create()
return@put pokemon.struct
}
map
}
)
val evolutionFunctions: MutableList<(Evolution) -> HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf(
{ evolution ->
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
map.put("result") { evolution.result.asMoLangValue() }
if (evolution is LevelUpEvolution) {
map.put("is_level_up") { DoubleValue.ONE }
} else if (evolution is TradeEvolution) {
map.put("is_trade") { DoubleValue.ONE }
} else if (evolution is ItemInteractionEvolution) {
map.put("is_item") { DoubleValue.ONE }
}
map.put("is_optional") { DoubleValue(evolution.optional) }
map.put("consumes_held_item") { DoubleValue(evolution.consumeHeldItem) }
map
}
)
fun ItemStack.asMoLangValue(registryAccess: RegistryAccess) = ObjectValue(this).addStandardFunctions().addFunctions(itemStackFunctions.flatMap { it(this, registryAccess).entries.map { it.key to it.value } }.toMap())
fun Holder<Biome>.asBiomeMoLangValue() = asMoLangValue(Registries.BIOME).addFunctions(biomeFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
fun Holder<Level>.asWorldMoLangValue() = asMoLangValue(Registries.DIMENSION).addFunctions(worldFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
fun Holder<Block>.asBlockMoLangValue() = asMoLangValue(Registries.BLOCK).addFunctions(blockFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
fun MinecraftServer.asMoLangValue() = ObjectValue(this).addStandardFunctions().addFunctions(serverFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
fun Holder<DimensionType>.asDimensionTypeMoLangValue() = asMoLangValue(Registries.DIMENSION_TYPE).addFunctions(dimensionTypeFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
fun Player.asMoLangValue(): ObjectValue<Player> {
if (this is ServerPlayer && uuid in Cobblemon.serverPlayerStructs) {
val existing = Cobblemon.serverPlayerStructs[uuid]!!
if (existing.obj == this) {
return existing
} else {
Cobblemon.serverPlayerStructs.remove(uuid)
}
}
val value = ObjectValue(
obj = this,
stringify = { it.effectiveName().string }
)
value.addFunctions(entityFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
value.addFunctions(livingEntityFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
value.addFunctions(playerFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
if (this is ServerPlayer) {
Cobblemon.serverPlayerStructs[uuid] = value
}
return value
}
@@ -1034,6 +1193,24 @@ object MoLangFunctions {
return value
}
fun PokemonProperties.asMoLangValue(): ObjectValue<PokemonProperties> {
val value = ObjectValue(
obj = this,
stringify = { it.asString() }
)
value.addFunctions(pokemonPropertiesFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
return value
}
fun Evolution.asMoLangValue(): ObjectValue<Evolution> {
val value = ObjectValue(
obj = this,
stringify = { it.toString() }
)
value.addFunctions(evolutionFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
return value
}
fun PCStore.asMoLangValue(): ObjectValue<PCStore> {
val value = ObjectValue(
obj = this,
@@ -1050,6 +1227,7 @@ object MoLangFunctions {
stringify = { it.name.string }
)
value.addFunctions(entityFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
value.addFunctions(livingEntityFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
value.addFunctions(npcFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
return value
}
@@ -1060,6 +1238,7 @@ object MoLangFunctions {
stringify = { it.pokemon.uuid.toString() }
)
value.addFunctions(entityFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
value.addFunctions(livingEntityFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
value.addFunctions(pokemonFunctions.flatMap { it(this.pokemon).entries.map { it.key to it.value } }.toMap()) // Convenience
value.addFunctions(pokemonEntityFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
return value
@@ -1095,12 +1274,18 @@ object MoLangFunctions {
/**
* Different functions exist depending on
*/
fun LivingEntity.asMostSpecificMoLangValue(): ObjectValue<out LivingEntity> {
fun Entity.asMostSpecificMoLangValue(): ObjectValue<out Entity> {
return when (this) {
is Player -> asMoLangValue()
is PokemonEntity -> struct
is NPCEntity -> struct
else -> ObjectValue(this).also { it.addStandardFunctions().addFunctions(entityFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap()) }
else -> ObjectValue(this).also {
it.addStandardFunctions()
it.addFunctions(entityFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
if (this is LivingEntity) {
it.addFunctions(livingEntityFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
}
}
}
}
@@ -1125,7 +1310,7 @@ object MoLangFunctions {
return this
}
fun QueryStruct.addEntityFunctions(entity: LivingEntity): QueryStruct {
fun QueryStruct.addEntityFunctions(entity: Entity): QueryStruct {
val addedFunctions = entityFunctions
.flatMap { it.invoke(entity).entries }
.associate { it.key to it.value }
@@ -1133,6 +1318,14 @@ object MoLangFunctions {
return this
}
fun QueryStruct.addLivingEntityFunctions(entity: LivingEntity): QueryStruct {
val addedFunctions = livingEntityFunctions
.flatMap { it.invoke(entity).entries }
.associate { it.key to it.value }
functions.putAll(addedFunctions)
return this
}
fun QueryStruct.addPokedexFunctions(pokedexManager: AbstractPokedexManager): QueryStruct {
val addedFunctions = pokedexFunctions
.flatMap { it.invoke(pokedexManager).entries }
@@ -1170,6 +1363,24 @@ object MoLangFunctions {
return this
}
fun moLangFunctionMap(
vararg functions: Pair<String, (MoParams) -> MoValue>
): Map<String, (MoParams) -> MoValue> {
return functions.toMap()
}
fun queryStructOf(
vararg functions: Pair<String, (MoParams) -> MoValue>
): QueryStruct {
return QueryStruct(
hashMapOf<String, java.util.function.Function<MoParams, Any>>(
*functions.map { (name, func) ->
name to java.util.function.Function<MoParams, Any> { params -> func(params) }
}.toTypedArray()
)
)
}
fun MoLangRuntime.setup(): MoLangRuntime {
environment.query.addStandardFunctions()
return this
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common.api.moves
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.IntSize
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.readSizedInt
@@ -24,7 +23,7 @@ import net.minecraft.nbt.ListTag
import net.minecraft.network.RegistryFriendlyByteBuf
class BenchedMoves : Iterable<BenchedMove> {
val observable = SimpleObservable<BenchedMoves>()
var changeFunction: ((BenchedMoves) -> Unit) = {}
private var emit = true
private val benchedMoves = mutableListOf<BenchedMove>()
@@ -50,7 +49,7 @@ class BenchedMoves : Iterable<BenchedMove> {
fun update() {
if (emit) {
observable.emit(this)
changeFunction(this)
}
}
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.api.moves
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.IntSize
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.readSizedInt
@@ -24,7 +23,7 @@ import com.mojang.serialization.Codec
import kotlin.math.min
class MoveSet : Iterable<Move> {
val observable = SimpleObservable<MoveSet>()
var changeFunction: (MoveSet) -> Unit = {}
private var emit = true
private val moves = arrayOfNulls<Move>(MOVE_COUNT)
@@ -153,7 +152,7 @@ class MoveSet : Iterable<Move> {
fun update() {
if (emit) {
observable.emit(this)
changeFunction(this)
}
}
@@ -166,7 +166,7 @@ open class MoveTemplate(
// TODO: Handle Liquid Voice: need to know what moves have the sound flag
// TODO: Handle weatherball, naturalgift, judgement, technoblast, terrainpulse, and terrablast
if (this.elementalType == ElementalTypes.NORMAL) {
if( this.damageCategory != DamageCategories.STATUS) {
if (this.damageCategory != DamageCategories.STATUS) {
return when (pokemon.ability.name) {
"pixilate" -> ElementalTypes.FAIRY
"aerilate" -> ElementalTypes.FLYING
@@ -7,27 +7,31 @@
*/
package com.cobblemon.mod.common.api.npc.partyproviders
import com.bedrockk.molang.Expression
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.npc.NPCPartyProvider
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.storage.party.NPCPartyStore
import com.cobblemon.mod.common.entity.npc.NPCEntity
import com.cobblemon.mod.common.util.asArrayValue
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.resolveFloat
import com.cobblemon.mod.common.util.resolveInt
import com.cobblemon.mod.common.util.weightedSelection
import com.cobblemon.mod.common.util.withQueryValue
import com.cobblemon.mod.common.util.*
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive
import kotlin.random.Random
import net.minecraft.server.level.ServerPlayer
import kotlin.collections.List
import kotlin.collections.any
import kotlin.collections.filter
import kotlin.collections.first
import kotlin.collections.mutableListOf
import kotlin.collections.mutableMapOf
import kotlin.collections.randomOrNull
import kotlin.collections.set
import kotlin.collections.toMutableList
import kotlin.random.Random
/**
* A provider of a party for battling the NPC. It generates a party using a more complex process
@@ -60,9 +64,9 @@ class PoolPartyProvider : NPCPartyProvider {
json as JsonObject
this.minPokemon = json.getAsJsonPrimitive("minPokemon").asString?.asExpression() ?: "1".asExpression()
this.maxPokemon = json.getAsJsonPrimitive("maxPokemon").asString?.asExpression() ?: "6".asExpression()
this.pool = json.getAsJsonArray("pool").map {
this.pool = json.getAsJsonArray("pool").mapNotNull {
if (it is JsonPrimitive) {
return@map DynamicPokemon(
return@mapNotNull DynamicPokemon(
PokemonProperties.parse(it.asString),
"0".asExpression(),
null,
@@ -73,17 +77,26 @@ class PoolPartyProvider : NPCPartyProvider {
}
it as JsonObject
DynamicPokemon(
PokemonProperties.parse(it.get("pokemon").asString),
it.get("levelVariation")?.asString?.asExpression() ?: "0".asExpression(),
it.get("level")?.asString?.asExpression(),
it.get("npcLevels")?.asString?.split("-")?.let { it[0].toInt()..it[1].toInt() } ?: 1..100,
it.get("selectableTimes")?.asString?.asExpression() ?: "1".asExpression(),
it.get("weight")?.asString?.asExpression() ?: "1".asExpression()
)
val properties = PokemonProperties.parse(it.get("pokemon").asString)
// Checks for errors on Pokémon name, if not a valid species ignores it to avoid random Pokémon in the Pool.
if (properties.species == null) {
LOGGER.warn("Error making NPC pokemon pool. ${it.get("pokemon").asString.substringBefore(" ")} is not a valid species, ignoring")
null
}
else {
DynamicPokemon(
properties,
it.get("levelVariation")?.asString?.asExpression() ?: "0".asExpression(),
it.get("level")?.asString?.asExpression(),
it.get("npcLevels")?.asString?.split("-")?.let { it[0].toInt()..it[1].toInt() } ?: 1..100,
it.get("selectableTimes")?.asString?.asExpression() ?: "1".asExpression(),
it.get("weight")?.asString?.asExpression() ?: "1".asExpression()
)
}
}.toMutableList()
isStatic = json.get("isStatic").asBoolean
json.get("useFixedRandom")?.asBoolean?.let { useFixedRandom = it }
}
class DynamicPokemon(
@@ -137,6 +150,10 @@ class PoolPartyProvider : NPCPartyProvider {
val instance = selected.pokemon.copy().also { it.level = it.level ?: dictatedLevel ?: randomLevel }.create()
party.add(instance)
}
if (party.none()) {
LOGGER.error("${npc} has no Pokemon on Party")
}
}
override fun provide(npc: NPCEntity, level: Int, players: List<ServerPlayer>): NPCPartyStore {
@@ -13,81 +13,124 @@ object CobblemonPermissions {
private const val COMMAND_PREFIX = "command."
private val permissions = arrayListOf<Permission>()
@JvmStatic
val CHANGE_EYE_HEIGHT = this.create("${COMMAND_PREFIX}changeeyeheight", PermissionLevel.ALL_COMMANDS)
@JvmStatic
val CHANGE_SCALE_AND_SIZE = this.create("${COMMAND_PREFIX}changescaleandsize", PermissionLevel.ALL_COMMANDS)
@JvmStatic
val CHANGE_WALK_SPEED = this.create("${COMMAND_PREFIX}changewalkspeed", PermissionLevel.ALL_COMMANDS)
@JvmStatic
val CHANGE_JOINT_SCALE = this.create("${COMMAND_PREFIX}changejointscale", PermissionLevel.ALL_COMMANDS)
@JvmStatic
val CHECKSPAWNS = this.create("${COMMAND_PREFIX}checkspawns", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val GET_NBT = this.create("${COMMAND_PREFIX}getnbt", PermissionLevel.ALL_COMMANDS)
private const val GIVE_POKEMON_BASE = "${COMMAND_PREFIX}givepokemon"
@JvmStatic
val GIVE_POKEMON_SELF = this.create("${GIVE_POKEMON_BASE}.self", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val GIVE_POKEMON_OTHER = this.create("${GIVE_POKEMON_BASE}.other", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
private const val HEAL_POKEMON_BASE = "${COMMAND_PREFIX}healpokemon"
@JvmStatic
val HEAL_POKEMON_SELF = this.create("$HEAL_POKEMON_BASE.self", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val HEAL_POKEMON_OTHER = this.create("$HEAL_POKEMON_BASE.other", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
private const val LEVEL_UP_BASE = "${COMMAND_PREFIX}levelup"
@JvmStatic
val LEVEL_UP_SELF = this.create("$LEVEL_UP_BASE.self", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val LEVEL_UP_OTHER = this.create("$LEVEL_UP_BASE.other", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val OPEN_STARTER_SCREEN = this.create("${COMMAND_PREFIX}openstarterscreen", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val BEDROCK_PARTICLE = this.create("${COMMAND_PREFIX}bedrockparticle", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val OPEN_DIALOGUE = this.create("${COMMAND_PREFIX}opendialogue", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val UNLOCK_PC_BOX_WALLPAPER = this.create("${COMMAND_PREFIX}unlockpcboxwallpaper", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
private const val POKEMON_EDIT_BASE = "${COMMAND_PREFIX}pokemonedit"
@JvmStatic
val POKEMON_EDIT_SELF = this.create("$POKEMON_EDIT_BASE.self", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val POKEMON_EDIT_OTHER = this.create("$POKEMON_EDIT_BASE.other", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val SPAWN_ALL_POKEMON = this.create("${COMMAND_PREFIX}spawnallpokemon", PermissionLevel.ALL_COMMANDS)
@JvmStatic
val GIVE_ALL_POKEMON = this.create("${COMMAND_PREFIX}giveallpokemon", PermissionLevel.ALL_COMMANDS)
@JvmStatic
val SPAWN_POKEMON = this.create("${COMMAND_PREFIX}spawnpokemon", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val SPAWN_NPC = this.create("${COMMAND_PREFIX}spawnnpc", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val STOP_BATTLE = this.create("${COMMAND_PREFIX}stopbattle", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val TAKE_POKEMON = this.create("${COMMAND_PREFIX}takepokemon", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val TEACH = this.create("${COMMAND_PREFIX}teach.base", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val TEACH_BYPASS_LEARNSET = this.create("${COMMAND_PREFIX}teach.bypass", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val FRIENDSHIP = this.create("${COMMAND_PREFIX}friendship", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val HELD_ITEM = this.create("${COMMAND_PREFIX}helditem", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val PC = this.create("${COMMAND_PREFIX}pc", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val POKEBOX = this.create("${COMMAND_PREFIX}pokebox", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val RENAMEBOX = this.create("${COMMAND_PREFIX}renamebox", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val CHANGE_WALLPAPER = this.create("${COMMAND_PREFIX}changewallpaper", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val TEST_STORE = this.create("${COMMAND_PREFIX}teststore", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val QUERY_LEARNSET = this.create("${COMMAND_PREFIX}querylearnset", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val TEST_PC_SLOT = this.create("${COMMAND_PREFIX}testpcslot", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val TEST_PARTY_SLOT = this.create("${COMMAND_PREFIX}testpartyslot", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val CLEAR_PARTY = this.create("${COMMAND_PREFIX}clearparty", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val CLEAR_PC = this.create("${COMMAND_PREFIX}clearpc", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val POKEDEX = this.create("${COMMAND_PREFIX}pokedex", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val NPC_EDIT = this.create("${COMMAND_PREFIX}npcedit", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val NPC_DELETE = this.create("${COMMAND_PREFIX}npcdelete", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val FREEZE_POKEMON = this.create("${COMMAND_PREFIX}freezepokemon", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val APPLY_PLAYER_TEXTURE = this.create("${COMMAND_PREFIX}applyplayertexture", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val ABANDON_MULTITEAM = this.create("${COMMAND_PREFIX}abandonmultiteam", PermissionLevel.NONE)
@JvmStatic
val RUN_MOLANG_SCRIPT = this.create("${COMMAND_PREFIX}runmolangscript", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val COBBLEMON_CONFIG_RELOAD = this.create("${COMMAND_PREFIX}cobblemonconfig.reload", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
val CALCULATE_SEAT_POSITIONS = this.create("${COMMAND_PREFIX}calculateseatpositions", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
fun all(): Iterable<Permission> = this.permissions
private fun create(node: String, level: PermissionLevel): Permission {
@@ -8,9 +8,6 @@
package com.cobblemon.mod.common.api.pokemon
import com.bedrockk.molang.runtime.struct.VariableStruct
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.abilities.Abilities
import com.cobblemon.mod.common.api.abilities.Ability
@@ -725,8 +722,8 @@ open class PokemonProperties {
nature = json.get(DataKeys.POKEMON_NATURE)?.asString
ability = json.get(DataKeys.POKEMON_ABILITY)?.asString
status = json.get(DataKeys.POKEMON_STATUS_NAME)?.asString
ivs = json.getAsJsonObject(DataKeys.POKEMON_IVS)?.let { IVs().loadFromJSON(it) } as IVs
evs = json.getAsJsonObject(DataKeys.POKEMON_EVS)?.let { EVs().loadFromJSON(it) } as EVs
ivs = json.getAsJsonObject(DataKeys.POKEMON_IVS)?.let { IVs().loadFromJSON(it) } as? IVs
evs = json.getAsJsonObject(DataKeys.POKEMON_EVS)?.let { EVs().loadFromJSON(it) } as? EVs
type = json.get(DataKeys.ELEMENTAL_TYPE)?.asString
teraType = json.get(DataKeys.POKEMON_TERA_TYPE)?.asString
dmaxLevel = json.get(DataKeys.POKEMON_DMAX_LEVEL)?.asInt
@@ -775,17 +772,6 @@ open class PokemonProperties {
return pieces.joinToString(separator)
}
fun asStruct(): VariableStruct {
val struct = VariableStruct()
species?.let { struct.setDirectly("species", StringValue(it)) }
level?.let { struct.setDirectly("level", DoubleValue(it)) }
shiny?.let { struct.setDirectly("shiny", DoubleValue(it)) }
// add more of the optional properties to the struct as doubles or strings
gender?.let { struct.setDirectly("gender", StringValue(it.name)) }
friendship?.let { struct.setDirectly("friendship", DoubleValue(it)) }
return struct
}
fun updateAspects() {
val aspects = mutableSetOf<String>()
AspectProvider.providers.forEach { aspects.addAll(it.provide(this)) }
@@ -11,9 +11,11 @@ package com.cobblemon.mod.common.api.pokemon
import com.cobblemon.mod.common.pokemon.Pokemon
enum class PokemonSortMode(val comparator: Comparator<Pokemon?>, val reverseComparator: Comparator<Pokemon?>) {
NAME( { it?.getDisplayName()?.string } ),
LEVEL( { it?.level } ),
TYPE( { it?.primaryType?.name } );
NAME({ it?.getDisplayName()?.string }),
LEVEL({ it?.level }),
TYPE({ it?.primaryType?.name }),
POKEDEX_NUMBER({ it?.species?.nationalPokedexNumber }),
GENDER({ it?.gender });
constructor(mapper: (Pokemon?) -> Comparable<*>?) : this(compareBy({ it == null }, mapper),
compareBy<Pokemon?> { it == null }.thenComparing(compareBy(mapper).reversed()))
@@ -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,8 @@ 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.riding.stats.RidingStatDefinition
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
@@ -45,6 +48,7 @@ import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonRequirementA
import com.cobblemon.mod.common.pokemon.evolution.adapters.LegacyItemConditionWrapperAdapter
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
import com.cobblemon.mod.common.util.adapters.*
import com.cobblemon.mod.common.util.adapters.RideControllerAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.common.collect.HashBasedTable
import com.google.gson.Gson
@@ -53,6 +57,7 @@ import com.google.gson.reflect.TypeToken
import net.minecraft.advancements.critereon.ItemPredicate
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
@@ -93,6 +98,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
.registerTypeAdapter(DropEntry::class.java, DropEntryAdapter)
.registerTypeAdapter(CompoundTag::class.java, NbtCompoundAdapter)
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
.registerTypeAdapter(Component::class.java, TextAdapter)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, BiomeLikeConditionAdapter)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, BlockLikeConditionAdapter)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Item::class.java).type, ItemLikeConditionAdapter)
@@ -100,6 +106,9 @@ object PokemonSpecies : JsonDataRegistry<Species> {
.registerTypeAdapter(EggGroup::class.java, EggGroupAdapter)
.registerTypeAdapter(MobEffect::class.java, RegistryElementAdapter<MobEffect>(BuiltInRegistries::MOB_EFFECT))
.registerTypeAdapter(ItemPredicate::class.java, LegacyItemConditionWrapperAdapter)
.registerTypeAdapter(RideController::class.java, RideControllerAdapter)
.registerTypeAdapter(RidingStatDefinition::class.java, RidingStatDefinitionAdapter)
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
.disableHtmlEscaping()
.enableComplexMapKeySerialization()
.create()
@@ -119,6 +128,11 @@ object PokemonSpecies : JsonDataRegistry<Species> {
init {
SpeciesAdditions.observable.subscribe {
this.species.forEach(Species::initialize)
this.species.forEach {
if (it.implemented) {
this.implemented.add(it)
}
}
this.species.forEach(Species::resolveEvolutionMoves)
Cobblemon.showdownThread.queue {
it.registerSpecies()
@@ -197,9 +211,6 @@ object PokemonSpecies : JsonDataRegistry<Species> {
this.speciesByDex.remove(old.resourceIdentifier.namespace, old.nationalPokedexNumber)
}
this.speciesByDex.put(species.resourceIdentifier.namespace, species.nationalPokedexNumber, species)
if (species.implemented) {
this.implemented.add(species)
}
}
}
@@ -176,7 +176,7 @@ interface Evolution : EvolutionLike {
pokemonEntity.after(11.2F) {
evolutionMethod(pokemon)
}
pokemonEntity.after( seconds = 12F ) {
pokemonEntity.after(seconds = 12F) {
cryAnimation(pokemonEntity)
pokemonEntity.entityData.set(PokemonEntity.EVOLUTION_STARTED, false)
pokemon.getOwnerPlayer()?.sendSystemMessage(lang("ui.evolve.into", preEvoName, pokemon.species.translatedName))
@@ -68,8 +68,8 @@ object SpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
data.forEach(this::registerFromAssets)
}
fun getCodeFeature(name: String) = resourceFeatures[name]
fun getResourceFeature(name: String) = codeFeatures[name]
fun getCodeFeature(name: String) = codeFeatures[name]
fun getResourceFeature(name: String) = resourceFeatures[name]
fun getFeature(name: String) = getCodeFeature(name) ?: getResourceFeature(name)
fun loadOnClient(entries: Collection<Map.Entry<String, SpeciesFeatureProvider<*>>>) {
codeFeatures.putAll(entries.map { it.toPair() })
@@ -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.7.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,215 @@
/*
* 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.Rollable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.riding.controller.RideController
import com.cobblemon.mod.common.api.riding.stats.RidingStat
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.toProperties
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.ChatFormatting
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
import net.minecraft.util.SmoothDouble
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
import kotlin.math.sin
import kotlin.math.sin
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()) }
it.environment.query.addFunction("get_ride_stats") { params ->
val rideStat = RidingStat.valueOf(params.getString(0).uppercase())
val rideStyle = RidingStyle.valueOf(params.getString(1).uppercase())
val maxVal = params.getDouble(2)
val minVal = params.getDouble(3)
//TODO: Use the mons actual boost once implemented
val normalizedStat = entity.rideProp.calculate(rideStat, rideStyle, 0) / 100.0f
val trueStatVal = (normalizedStat * (maxVal - minVal)) + minVal
DoubleValue(trueStatVal)
}
}
}
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)
//val speedPlayer = driver.deltaMovement.horizontalDistance()
//driver.displayClientMessage(Component.literal("Speed player: ").withStyle { it.withColor(ChatFormatting.GREEN) }.append(Component.literal("$speedPlayer b/t")), true)
//val speedEntity = entity.deltaMovement.length() //* 20 * 60 * 60) / ( 1000 )
//println(speedEntity)
//driver.displayClientMessage(Component.literal("Speed: ").withStyle { it.withColor(ChatFormatting.GREEN) }.append(Component.literal("${String.format("%.2f", speedEntity)} km/h")), 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 setRideBar(entity: PokemonEntity, driver: Player): Float {
val controller = getController(entity) ?: return 0.0f
return controller.setRideBar(entity, driver)
}
fun rideFovMult(entity: PokemonEntity, driver: Player): Float {
val controller = getController(entity) ?: return 1.0f
return controller.rideFovMult(entity, driver)
}
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)
}
/**
* Used to supply the delta for the lerp() between velocity
* vectors. Called inertia for now as the way it feels when
* affecting the ride is somewhat akin to inertia.
*/
fun inertia(entity: PokemonEntity): Double {
val controller = getController(entity) ?: return 0.5
return controller.inertia(entity)
}
fun gravity(entity: PokemonEntity, regularGravity: Double): Double? {
val controller = getController(entity) ?: return null
return controller.gravity(entity, regularGravity)
}
//Maybe should be changed to be a function that conveys:
// "turn on use our camera system function"
fun shouldRoll(entity: PokemonEntity): Boolean {
val controller = getController(entity) ?: return false
return controller.shouldRoll(entity)
}
fun shouldRotatePlayerHead(entity: PokemonEntity): Boolean {
val controller = getController(entity) ?: return false
return controller.shouldRotatePlayerHead()
}
fun shouldRotatePokemonHead(entity: PokemonEntity): Boolean {
val controller = getController(entity) ?: return false
return controller.shouldRotatePokemonHead()
}
fun rotationOnMouseXY(
entity: PokemonEntity,
driver: Player,
yMouse: Double,
xMouse: Double,
yMouseSmoother: SmoothDouble,
xMouseSmoother: SmoothDouble,
sensitivity: Double,
deltaTime: Double
): Vec3 {
val controller = getController(entity) ?: return Vec3.ZERO
return controller.rotationOnMouseXY(
entity,
driver,
yMouse,
xMouse,
yMouseSmoother,
xMouseSmoother,
sensitivity,
deltaTime
) }
/**
* Determines whether mouse input will affect the rotation of
* the rollable object. Need to remove this as it's not used anymore
*/
//I think this might better serve as a "use smoothing on angular velocity"
fun useAngVelSmoothing(entity: PokemonEntity): Boolean {
val controller = getController(entity) ?: return true
return controller.useAngVelSmoothing(entity)
}
fun turnOffOnGround(entity: PokemonEntity): Boolean {
val controller = getController(entity) ?: return false
return controller.turnOffOnGround(entity)
}
fun angRollVel(entity: PokemonEntity, driver: Player, deltaTime: Double): Vec3 {
val controller = getController(entity) ?: return Vec3(0.0, 0.0, 0.0)
return controller.angRollVel(entity, driver, deltaTime)
}
fun dismountOnShift(): Boolean {
val controller = getController(entity) ?: return false
return controller.dismountOnShift(entity)
}
}
@@ -0,0 +1,70 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.api.riding.controller.RideController
import com.cobblemon.mod.common.api.riding.stats.RidingStat
import com.cobblemon.mod.common.api.riding.stats.RidingStatDefinition
import com.cobblemon.mod.common.util.adapters.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 stats: Map<RidingStat, RidingStatDefinition> = mapOf(),
val seats: List<Seat> = listOf(),
val conditions: List<Expression> = listOf(),
val controller: RideController? = null
) {
companion object {
fun decode(buffer: RegistryFriendlyByteBuf): RidingProperties {
val stats: Map<RidingStat, RidingStatDefinition> = buffer.readMap(
{ buffer.readEnum<RidingStat>(RidingStat::class.java) },
{ RidingStatDefinition.decode(buffer) }
)
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(stats = stats, seats = seats, conditions = conditions, controller = controller)
}
}
val canRide: Boolean
get() = seats.isNotEmpty() && controller != null
fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeMap(
stats,
{ _, stat -> buffer.writeEnum(stat) },
{ _, stat -> stat.encode(buffer) }
)
buffer.writeCollection(seats) { _, seat -> seat.encode(buffer) }
buffer.writeCollection(conditions) { _, condition -> buffer.writeString(condition.getString()) }
buffer.writeNullable(controller) { _, controller -> controller.encode(buffer) }
}
fun calculate(stat: RidingStat, style: RidingStyle, boosts: Int): Float {
val definitions = stats[stat] ?: return 0F
return definitions.calculate(style, boosts)
}
fun hasStat(stat: RidingStat, style: RidingStyle): Boolean {
return stats[stat]?.ranges?.containsKey(style) == true
}
}
@@ -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,22 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding
/**
* A general medium for riding. Mainly used for categorizing which stats to pull from and for
* presenting a simplified view of riding to users.
*
* @author Hiroku
* @since February 17th, 2025
*/
enum class RidingStyle {
LAND,
LIQUID,
AIR
}
@@ -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,151 @@
/*
* 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.Cobblemon
import com.cobblemon.mod.common.Rollable
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.util.SmoothDouble
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
/**
* 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 1.7.0
*/
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
/**
* Sets the change current change in rotation for that tick in three
* dimensions
*/
fun angRollVel(entity: PokemonEntity, driver: Player, deltaTime: Double): Vec3 {
return Vec3(0.0, 0.0, 0.0)
}
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 setRideBar(entity: PokemonEntity, driver: Player): Float = 0.0f
fun rideFovMult(entity: PokemonEntity, driver: Player): Float = 1.0f
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 inertia(entity: PokemonEntity): Double = 0.5
fun shouldRoll(entity: PokemonEntity): Boolean = false
fun useAngVelSmoothing(entity: PokemonEntity): Boolean = false
//If function is not overwritten by controllers then just perform the defualt
//rolling function which is roll on mousex and pitch on mousey
fun rotationOnMouseXY(
entity: PokemonEntity,
driver: Player,
yMouse: Double,
xMouse: Double,
yMouseSmoother: SmoothDouble,
xMouseSmoother: SmoothDouble,
sensitivity: Double,
deltaTime: Double
): Vec3 {
if (driver !is Rollable) return Vec3.ZERO
//Might need to add the smoothing here for default.
val rollable = driver as Rollable
val invertRoll = if (Cobblemon.config.invertRoll) -1 else 1
val invertPitch = if (Cobblemon.config.invertPitch) -1 else 1
return Vec3(0.0, yMouse * invertPitch, xMouse * invertRoll)
}
fun turnOffOnGround(entity: PokemonEntity): Boolean = false
fun dismountOnShift(entity: PokemonEntity): Boolean = false
fun getRuntime(entity: PokemonEntity) = entity.riding.runtime
fun shouldRotatePokemonHead(): Boolean = false
fun shouldRotatePlayerHead(): Boolean = false
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)
}
@@ -0,0 +1,38 @@
/*
* 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.stats
import com.cobblemon.mod.common.api.berry.Flavor
import com.cobblemon.mod.common.util.lang
import net.minecraft.network.chat.Component
/**
* A stat that is used for riding Pokémon. The exact implementation of each of these depends on the [com.cobblemon.mod.common.api.riding.controller.RideController].
*
* @author Hiroku
* @since February 17th, 2025
*/
enum class RidingStat(
val flavour: Flavor
) {
SPEED(Flavor.SWEET),
ACCELERATION(Flavor.SPICY),
SKILL(Flavor.DRY),
JUMP(Flavor.BITTER),
STAMINA(Flavor.SOUR);
companion object {
fun getByName(name: String) = RidingStat.entries.firstOrNull { it.name.equals(name, ignoreCase = true) }
}
val displayName: Component
get() = lang("riding.stat.${name.lowercase()}.name")
val description: Component
get() = lang("riding.stat.${name.lowercase()}.desc")
}
@@ -0,0 +1,70 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding.stats
import com.cobblemon.mod.common.api.riding.RidingStyle
import com.cobblemon.mod.common.net.IntSize
import com.cobblemon.mod.common.util.readSizedInt
import com.cobblemon.mod.common.util.readText
import com.cobblemon.mod.common.util.writeSizedInt
import com.cobblemon.mod.common.util.writeText
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.network.chat.Component
/**
* The definition of all the different information related to a specific [RidingStat] on a Pokémon species.
*
* @author Hiroku
* @since February 17th, 2025
*/
class RidingStatDefinition {
// This object gets read from a JSON adapter manually (field-by-field) so don't add fields without updating the adapter.
/** A map from [RidingStyle] to a minimum and maximum value for this stat. */
val ranges = mutableMapOf<RidingStyle, IntRange>()
/** Display name for the stat, if null falls back to [RidingStat.displayName]. */
var displayName: Component? = null
/** Description for the stat, if null falls back to [RidingStat.description]. */
var description: Component? = null
fun calculate(style: RidingStyle, aprijuiceBoost: Int): Float {
val range = ranges[style] ?: ranges[RidingStyle.LAND] ?: return 0F
val boostQuotient = aprijuiceBoost / 255F
return range.first + (range.last - range.first) * boostQuotient
}
fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeNullable(displayName) { _, it -> buffer.writeText(it) }
buffer.writeNullable(description) { _, it -> buffer.writeText(it) }
buffer.writeMap(
ranges,
{ _, it -> buffer.writeEnum(it) },
{ _, it ->
buffer.writeSizedInt(IntSize.U_BYTE, it.first)
buffer.writeSizedInt(IntSize.U_BYTE, it.last)
}
)
}
companion object {
fun decode(buffer: RegistryFriendlyByteBuf): RidingStatDefinition {
val displayName = buffer.readNullable { buffer.readText() }
val description = buffer.readNullable { buffer.readText() }
val ranges = buffer.readMap<RidingStyle, IntRange>(
{ buffer.readEnum<RidingStyle>(RidingStyle::class.java) },
{ IntRange(buffer.readSizedInt(IntSize.U_BYTE), buffer.readSizedInt(IntSize.U_BYTE)) }
)
return RidingStatDefinition().apply {
this.displayName = displayName
this.description = description
this.ranges.putAll(ranges)
}
}
}
}
@@ -10,7 +10,14 @@ package com.cobblemon.mod.common.api.spawning
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.api.entity.Despawner
import com.cobblemon.mod.common.api.spawning.condition.*
import com.cobblemon.mod.common.api.spawning.condition.AreaSpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.BasicSpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.FishingSpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.GroundedSpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.SeafloorSpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.SubmergedSpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.SurfaceSpawningCondition
import com.cobblemon.mod.common.api.spawning.context.AreaContextResolver
import com.cobblemon.mod.common.api.spawning.context.FishingSpawningContext
import com.cobblemon.mod.common.api.spawning.context.GroundedSpawningContext
@@ -44,6 +51,7 @@ import com.cobblemon.mod.common.api.spawning.spawner.Spawner
import com.cobblemon.mod.common.api.spawning.spawner.TickingSpawner
import com.cobblemon.mod.common.entity.pokemon.CobblemonAgingDespawner
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.server.MinecraftServer
/**
* A grouping of all the overarching behaviours of the Best Spawner system. This is a convenient accessor to
@@ -130,7 +138,8 @@ object BestSpawner {
spawnerManagers.forEach(SpawnerManager::onConfigReload)
}
fun onServerStarted() {
fun onServerStarted(server: MinecraftServer) {
CobblemonSpawnPools.onServerLoad(server)
spawnerManagers.forEach(SpawnerManager::onServerStarted)
fishingSpawner = FishingSpawner()
}
@@ -8,10 +8,13 @@
package com.cobblemon.mod.common.api.spawning
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.spawning.condition.BiomePrecalculation
import com.cobblemon.mod.common.api.spawning.condition.BucketPrecalculation
import com.cobblemon.mod.common.api.spawning.condition.ContextPrecalculation
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.data.CobblemonDataProvider
import net.minecraft.server.MinecraftServer
/**
* A collection of all of Cobblemon's general-purpose [SpawnPool]s. These
@@ -26,6 +29,18 @@ object CobblemonSpawnPools {
lateinit var WORLD_SPAWN_POOL: SpawnPool
fun load() {
WORLD_SPAWN_POOL = CobblemonDataProvider.register(SpawnPool("world").addPrecalculators(ContextPrecalculation, BucketPrecalculation))
WORLD_SPAWN_POOL = CobblemonDataProvider.register(SpawnPool("world")
.addPrecalculators(
ContextPrecalculation,
BucketPrecalculation,
BiomePrecalculation
)
)
}
fun onServerLoad(server: MinecraftServer) {
Cobblemon.LOGGER.info("Optimizing spawn pools...")
WORLD_SPAWN_POOL.forEach { it.onServerLoad(server) }
WORLD_SPAWN_POOL.precalculate()
}
}
@@ -32,7 +32,7 @@ abstract class AreaTypeSpawningCondition<T : AreaSpawningContext> : SpawningCond
return false
} else if (maxHeight != null && ctx.height > maxHeight!!) {
return false
} else if (neededNearbyBlocks != null && neededNearbyBlocks!!.none { cond -> ctx.nearbyBlockTypes.any { cond.fits(it, ctx.blockRegistry) } }) {
} else if (neededNearbyBlocks != null && neededNearbyBlocks!!.none { cond -> ctx.nearbyBlockHolders.any { cond.fits(it) } }) {
return false
} else {
return true
@@ -10,6 +10,8 @@ package com.cobblemon.mod.common.api.spawning.condition
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import net.minecraft.core.Holder
import net.minecraft.world.level.biome.Biome
/**
* A spawning condition that is composed of a list of conditions and anticonditions.
@@ -30,6 +32,15 @@ class CompositeSpawningCondition {
var conditions = mutableListOf<SpawningCondition<*>>()
var anticonditions = mutableListOf<SpawningCondition<*>>()
fun isBiomeValid(holder: Holder<Biome>): Boolean {
if (conditions.isEmpty() || conditions.any { it.biomes == null || it.biomes!!.isEmpty() || it.biomes!!.any { it.fits(holder) } }) {
if (anticonditions.isEmpty() || anticonditions.none { it.biomes != null && it.biomes!!.any { it.fits(holder) } }) {
return true
}
}
return false
}
fun satisfiedBy(ctx: SpawningContext): Boolean {
return if (conditions.isNotEmpty() && conditions.none { it.isSatisfiedBy(ctx) }) {
false
@@ -30,7 +30,11 @@ abstract class GroundedTypeSpawningCondition<T : GroundedSpawningContext> : Area
return false
} else if (maxHeight != null && ctx.height > maxHeight!!) {
return false
} else !(neededBaseBlocks != null && neededBaseBlocks!!.none { it.fits(ctx.baseBlock.block, ctx.blockRegistry) })
} else if (neededBaseBlocks != null && neededBaseBlocks!!.none { it.fits(ctx.baseBlockHolder) }) {
return false
} else {
return true
}
}
override fun copyFrom(other: SpawningCondition<*>, merger: Merger) {
@@ -30,10 +30,14 @@ abstract class SeafloorTypeSpawningCondition<T : SeafloorSpawningContext> : Area
return if (!super.fits(ctx)) {
false
} else if (minHeight != null && ctx.height < minHeight!!) {
return false
false
} else if (maxHeight != null && ctx.height > maxHeight!!) {
return false
} else !(neededBaseBlocks != null && neededBaseBlocks!!.none { it.fits(ctx.baseBlock.block, ctx.blockRegistry) })
false
} else if (neededBaseBlocks != null && neededBaseBlocks!!.none { it.fits(ctx.baseBlockHolder) }) {
false
} else {
true
}
}
override fun copyFrom(other: SpawningCondition<*>, merger: Merger) {
@@ -44,7 +48,7 @@ abstract class SeafloorTypeSpawningCondition<T : SeafloorSpawningContext> : Area
}
override fun isValid(): Boolean {
val containsNullValues = neededBaseBlocks != null && neededBaseBlocks!!.any {it == null}
val containsNullValues = neededBaseBlocks != null && neededBaseBlocks!!.any { it == null }
return super.isValid() && !containsNullValues
}
}
@@ -42,6 +42,7 @@ abstract class SpawningCondition<T : SpawningContext> {
}
var dimensions: MutableList<ResourceLocation>? = null
/** This gets checked in a precalculation but still needs to be checked for things like rarity multipliers. */
var biomes: MutableSet<RegistryLikeCondition<Biome>>? = null
var moonPhase: MoonPhaseRange? = null
var canSeeSky: Boolean? = null
@@ -98,7 +99,7 @@ abstract class SpawningCondition<T : SpawningContext> {
return false
} else if (dimensions != null && dimensions!!.isNotEmpty() && ctx.world.dimensionType().effectsLocation !in dimensions!!) {
return false
} else if (biomes != null && biomes!!.isNotEmpty() && biomes!!.none { condition -> condition.fits(ctx.biome, ctx.biomeRegistry) }) {
} else if (biomes != null && biomes!!.isNotEmpty() && biomes!!.none { condition -> condition.fits(ctx.biomeHolder) }) {
return false
} else if (appendages.any { !it.fits(ctx) }) {
return false
@@ -153,11 +154,11 @@ abstract class SpawningCondition<T : SpawningContext> {
}
open fun isValid(): Boolean {
if(biomes != null && biomes!!.any {it == null})
if (biomes != null && biomes!!.any { it == null })
return false
if(dimensions != null && dimensions!!.any {it == null})
if (dimensions != null && dimensions!!.any { it == null })
return false
if(structures != null && structures!!.any {it == null})
if (structures != null && structures!!.any { it == null })
return false
return true
}
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
import net.minecraft.resources.ResourceLocation
/**
* A type of precalculation that can occur on a list of [SpawnDetail] to accelerate
@@ -31,7 +32,7 @@ import com.cobblemon.mod.common.api.spawning.spawner.Spawner
*/
interface SpawningPrecalculation<T : Any> {
/** Retrieves the precalculation keys for the given spawn detail. */
fun select(detail: SpawnDetail): List<T>
fun select(detail: SpawnDetail): Collection<T>
/** Retrieves the precalculation key for the given context, if that key exists for this context. */
fun select(ctx: SpawningContext): T?
@@ -71,7 +72,8 @@ interface SpawningPrecalculation<T : Any> {
* @since January 31st, 2022
*/
object RootPrecalculation : SpawningPrecalculation<Any> {
override fun select(detail: SpawnDetail): List<Any> = listOf(Unit)
val list = listOf(Unit)
override fun select(detail: SpawnDetail): List<Any> = list
override fun select(ctx: SpawningContext): Any = Unit
}
@@ -89,7 +91,15 @@ object ContextPrecalculation : SpawningPrecalculation<Class<out SpawningContext>
object BucketPrecalculation : SpawningPrecalculation<SpawnBucket> {
override fun select(detail: SpawnDetail) = listOf(detail.bucket)
override fun select(ctx: SpawningContext) = ctx.cause.bucket
}
/**
* This isn't so much of a precalculation as it is a yoinking of another precalculation.
* Uses pre-established [SpawnDetail.validBiomes] to shortcut knowing which spawns are valid for a biome.
*/
object BiomePrecalculation : SpawningPrecalculation<ResourceLocation> {
override fun select(detail: SpawnDetail) = detail.validBiomes
override fun select(ctx: SpawningContext) = ctx.biomeHolder.unwrapKey().map { it.location() }.orElse(null)
}
/**
@@ -18,6 +18,7 @@ import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.server.level.ServerLevel
import net.minecraft.core.BlockPos
import net.minecraft.core.Holder
/**
* A [SpawningContext] that is for a particular area, and therefore has spatial properties.
@@ -39,6 +40,7 @@ open class AreaSpawningContext(
val slice: WorldSlice
) : SpawningContext() {
val nearbyBlockTypes: List<Block> by lazy { nearbyBlocks.mapNotNull { it.block }.distinct() }
val nearbyBlockHolders: List<Holder<Block>> by lazy { nearbyBlockTypes.mapNotNull(blockRegistry::wrapAsHolder) }
override fun getStructureCache(pos: BlockPos): StructureChunkCache {
return slice.getStructureCache(pos)
@@ -11,9 +11,12 @@ package com.cobblemon.mod.common.api.spawning.context
import com.cobblemon.mod.common.api.spawning.SpawnCause
import com.cobblemon.mod.common.api.spawning.WorldSlice
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.util.blockRegistry
import net.minecraft.core.BlockPos
import net.minecraft.core.Holder
import net.minecraft.server.level.ServerLevel
import net.minecraft.tags.FluidTags
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.state.BlockState
/**
@@ -36,6 +39,7 @@ abstract class FlooredSpawningContext(
) : AreaSpawningContext(cause, world, position, light, skyLight, canSeeSky, influences, height, nearbyBlocks, slice) {
/** The block that the spawning is occurring on. */
val baseBlock = slice.getBlockState(position.x, position.y, position.z)
val baseBlockHolder: Holder<Block> by lazy { world.blockRegistry.wrapAsHolder(baseBlock.block) }
}
/**
@@ -82,7 +82,9 @@ abstract class SpawningContext {
/** The current phase of the moon at this location. */
val moonPhase: Int by lazy { world.moonPhase }
/** The biome of this location. */
val biome: Biome by lazy { world.getBiome(position).value() }
val biome: Biome by lazy { biomeHolder.value() }
/** The registry holder for the biome this context is in. */
val biomeHolder: Holder<Biome> by lazy { world.getBiome(position) }
val biomeRegistry: Registry<Biome> by lazy { world.registryAccess().registryOrThrow(Registries.BIOME) }
val blockRegistry: Registry<Block> by lazy { world.registryAccess().registryOrThrow(Registries.BLOCK) }
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.api.spawning.SpawnCause
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import net.minecraft.server.level.ServerLevel
import net.minecraft.tags.BlockTags
import net.minecraft.tags.FluidTags
import net.minecraft.world.level.block.state.BlockState
@@ -29,7 +30,7 @@ import net.minecraft.world.level.block.state.BlockState
*/
interface SpawningContextCalculator<I : SpawningContextInput, O : SpawningContext> {
companion object {
val isAirCondition: (BlockState) -> Boolean = { it.isAir || (!it.isSolid && !it.fluidState.`is`(FluidTags.WATER)) }
val isAirCondition: (BlockState) -> Boolean = { it.isAir || (!it.isSolid && !it.fluidState.`is`(FluidTags.WATER) && !it.`is`(BlockTags.RAILS)) }
val isSolidCondition: (BlockState) -> Boolean = { it.isSolid }
val isWaterCondition: (BlockState) -> Boolean = { it.fluidState.`is`(FluidTags.WATER) && it.fluidState.isSource }
val isLavaCondition: (BlockState) -> Boolean = { it.fluidState.`is`(FluidTags.LAVA) && it.fluidState.isSource }
@@ -8,9 +8,11 @@
package com.cobblemon.mod.common.api.spawning.detail
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.Cobblemon.config
import com.cobblemon.mod.common.api.drop.DropTable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
@@ -20,8 +22,8 @@ import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.asTranslated
import com.cobblemon.mod.common.util.lang
import com.google.gson.annotations.SerializedName
import net.minecraft.network.chat.MutableComponent
import kotlin.math.ceil
import net.minecraft.network.chat.MutableComponent
/**
* A [SpawnDetail] for spawning a [PokemonEntity].
@@ -69,7 +71,9 @@ class PokemonSpawnDetail : SpawnDetail() {
}
override fun autoLabel() {
val pokemonStruct = pokemon.asStruct()
struct.addFunction("pokemon") { pokemon.asMoLangValue() }
struct.addFunction("min_level") { DoubleValue(getDerivedLevelRange().start.toDouble()) }
struct.addFunction("max_level") { DoubleValue(getDerivedLevelRange().endInclusive.toDouble()) }
if (pokemon.species != null) {
val species = PokemonSpecies.getByIdentifier(pokemon.species!!.asIdentifierDefaultingNamespace())
if (species != null) {
@@ -88,7 +92,6 @@ class PokemonSpawnDetail : SpawnDetail() {
}
}
struct.setDirectly("pokemon", pokemonStruct)
super.autoLabel()
}
@@ -8,12 +8,12 @@
package com.cobblemon.mod.common.api.spawning.detail
import com.bedrockk.molang.runtime.struct.ArrayStruct
import com.bedrockk.molang.runtime.struct.VariableStruct
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.api.ModDependant
import com.cobblemon.mod.common.api.molang.MoLangFunctions.queryStructOf
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.condition.CompositeSpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
@@ -21,7 +21,11 @@ import com.cobblemon.mod.common.api.spawning.context.RegisteredSpawningContext
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.multiplier.WeightMultiplier
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.util.asArrayValue
import com.cobblemon.mod.common.util.asTranslated
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.MinecraftServer
/**
* A spawnable unit in the Best Spawner API. This is extended for any kind of entity
@@ -55,24 +59,49 @@ abstract class SpawnDetail : ModDependant {
var labels = mutableListOf<String>()
val struct: VariableStruct = VariableStruct()
/**
* This is calculated when the server starts. It is a set of all biome identifiers in which this spawn
* is possible. It is used as part of the [com.cobblemon.mod.common.api.spawning.condition.BiomePrecalculation].
*/
@Transient
val validBiomes = mutableSetOf<ResourceLocation>()
@Transient
val struct: QueryStruct = queryStructOf(
"weight" to { DoubleValue(weight) },
"percentage" to { DoubleValue(percentage) },
"id" to { StringValue(id) },
"bucket" to { StringValue(bucket.name) },
"width" to { DoubleValue(width.toDouble()) },
"height" to { DoubleValue(height.toDouble()) },
"context" to { StringValue(context.name) },
"labels" to { labels.asArrayValue { StringValue(it) } }
)
override var neededInstalledMods = listOf<String>()
override var neededUninstalledMods = listOf<String>()
open fun autoLabel() {
struct.setDirectly("weight", DoubleValue(weight.toDouble()))
struct.setDirectly("percentage", DoubleValue(percentage.toDouble()))
struct.setDirectly("id", StringValue(id))
struct.setDirectly("bucket", StringValue(bucket.name))
struct.setDirectly("width", DoubleValue(width.toDouble()))
struct.setDirectly("height", DoubleValue(height.toDouble()))
struct.setDirectly("context", StringValue(context.name))
struct.setDirectly("labels", ArrayStruct(labels.mapIndexed { index, s -> "$index" to StringValue(s) }.toMap()))
}
open fun autoLabel() {}
open fun getName() = displayName?.asTranslated() ?: id.text()
open fun onServerLoad(server: MinecraftServer) {
val biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME)
validBiomes.clear()
// Calculate in advance what biomes of this world the spawn detail is valid for.
biomeRegistry.holders().forEach { holder ->
val key = holder.unwrapKey().orElse(null) ?: return@forEach
if (conditions.isEmpty() || conditions.any { it.biomes == null || it.biomes!!.isEmpty() || it.biomes!!.any { it.fits(holder) } }) {
if (anticonditions.isEmpty() || anticonditions.none { it.biomes != null && it.biomes!!.any { it.fits(holder) } }) {
if (compositeCondition?.isBiomeValid(holder) != false) {
validBiomes.add(key.location())
}
}
}
}
}
open fun isSatisfiedBy(ctx: SpawningContext): Boolean {
if (!ctx.preFilter(this)) {
return false
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.api.spawning.detail
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
import com.cobblemon.mod.common.api.spawning.SpawnLoader
import com.cobblemon.mod.common.api.spawning.SpawnSet
import com.cobblemon.mod.common.api.spawning.condition.PrecalculationResult
@@ -18,6 +19,7 @@ import com.cobblemon.mod.common.api.spawning.condition.SpawningPrecalculation
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.server
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import net.minecraft.resources.ResourceLocation
@@ -48,6 +50,10 @@ class SpawnPool(val name: String) : JsonDataRegistry<SpawnSet>, Iterable<SpawnDe
for (set in data.values) {
details.addAll(set.filter { it.isValid() })
}
val server = server()
if (server != null && server.isRunning) {
CobblemonSpawnPools.onServerLoad(server)
}
precalculate()
}
@@ -1,51 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.influence
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import net.minecraft.tags.BlockTags
/**
* Implements a [SpawningInfluence] that prevents Pokémon spawning on certain blocks.
* This ensures that Pokémon don't spawn in areas that could disrupt player-built structures or mechanisms.
* The influence checks the block directly above the potential spawn location; if the block is in the restricted list,
* the spawn is disallowed.
*
* @author Aethen
* @since February 20th, 2024
*/
open class RestrictedSpawnBlocksInfluence
: SpawningInfluence {
// The list of blocks that Pokémon are not allowed to spawn on.
private val restrictedBlocks = BlockTags.RAILS
/**
* Affects the spawnable status of a Pokémon spawn detail.
* If the block directly above the spawn location is in the restricted list, the spawn is disallowed.
*
* @param detail The Pokémon spawn detail to be affected.
* @param ctx The context of the spawning event.
* @return `true` if the spawn is allowed, `false` if it is disallowed.
*/
override fun affectSpawnable(detail: SpawnDetail, ctx: SpawningContext): Boolean {
// If the spawn detail is not a Pokémon, it is not affected by this influence.
if (detail.type != "pokemon") return true
// Get the position of the potential spawn location.
val pokemonSpawnPos = ctx.position
// Examine the block immediately above the spawn block to check for a rail
// Potentially need a refactor if we ever want to check the spawn block itself.
return ctx.world.getBlockState(pokemonSpawnPos.atY(pokemonSpawnPos.y + 1)).`is`(restrictedBlocks).not()
}
}
@@ -66,9 +66,12 @@ abstract class AreaSpawner(
if (constrainedArea != null) {
val areaBox = AABB.ofSize(
Vec3(
constrainedArea.getCenter().toVec3f()
), CHUNK_REACH * 16.0 * 2, 1000.0, CHUNK_REACH * 16.0 * 2)
Vec3(constrainedArea.getCenter().toVec3f()),
CHUNK_REACH * 16.0 * 2,
1000.0,
CHUNK_REACH * 16.0 * 2
)
if (!constrainedArea.world.isBoxLoaded(areaBox)) {
return null
}
@@ -142,7 +145,7 @@ abstract class AreaSpawner(
break
} else if (isValidStartPoint(area.world, chunk, basePos.setY(originalY - offset))) {
valid = true
basePos.y = originalY + offset
basePos.y = originalY - offset
break
}
offset++
@@ -14,7 +14,6 @@ import com.cobblemon.mod.common.api.spawning.SpawnerManager
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.api.spawning.influence.PlayerLevelRangeInfluence
import com.cobblemon.mod.common.api.spawning.influence.PlayerLevelRangeInfluence.Companion.TYPICAL_VARIATION
import com.cobblemon.mod.common.api.spawning.influence.RestrictedSpawnBlocksInfluence
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.api.spawning.rules.SpawnRule
import com.cobblemon.mod.common.util.mutableLazy
@@ -45,7 +44,7 @@ object PlayerSpawnerFactory {
it,
variation = TYPICAL_VARIATION
)
}, { RestrictedSpawnBlocksInfluence() })
})
fun create(spawnerManager: SpawnerManager, player: ServerPlayer): PlayerSpawner {
val influences = influenceBuilders.mapNotNull { it(player) }

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