Compare commits

..
Author SHA1 Message Date
dhi_holo ada7f0faf8 Missed some
should be all clean now
2025-06-07 16:11:43 +10:00
dhi_holo e1eff89259 Update en_us.json 2025-06-07 15:36:24 +10:00
dhi_holo cc149a0ff2 They're made of Copper!
We decided that the set name should be copper, so I renamed it all.
2025-06-07 15:35:10 +10:00
dhi_holo 3fea718766 Merge branch 'main' into mechanical-hands 2025-06-07 14:10:34 +10:00
Polymeta c99bf99052 correct pokemon model item offset and GUI lighting
Closes #1597

Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-06-07 00:40:52 +01:00
Polymeta e8019a0623 make model loading not crash the game if a non-cobblemon model gets caught up in the parsing
Closes #1593

Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-06-06 17:05:29 +01:00
Polymeta 4c95cfc1b3 some neoforge fixes
Closes #1437

Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-06-06 16:19:54 +01:00
Polymeta 51a096913d simplify HeartyGrainsItem logic and update survival conditions for HeartyGrainsBlock to use tags
Closes #1591

Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-06-06 11:58:23 +01:00
Polymeta 980d95819e make DrowsySensor consider sleep status to allow it to wake/sleep during battles no matter the time
Closes #1554
Closes #1596

Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-06-06 01:19:34 +01:00
Polymeta 24aa65b2f1 Merge branch 'POLISH-POLISH' into 'main'
Little bit of refactoring

See merge request cable-mc/cobblemon!1699
2025-06-05 15:45:40 +00:00
Polymeta 19f33fe530 small cleanup and move component to correct place
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-06-05 16:02:32 +01:00
Polymeta bbe8a6948a fix license, refactor saplingblock and make falldamagemultiplier configurable
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-06-05 14:32:52 +01:00
Hiroku e46aaa5725 Merge branch 'party-select-tooltips' into 'main'
Adds a hoverText option to Party Select Callbacks.

See merge request cable-mc/cobblemon!1700
2025-06-05 11:08:34 +00:00
DeltricandHiroku fc6c302c71 Adds a hoverText option to Party Select Callbacks. 2025-06-05 11:08:34 +00:00
dhi_holo 76cf856907 Update CobblemonBlocks.kt
Didn't work properly, damn private classes
2025-06-05 20:46:43 +10:00
dhi_holo 145d56e205 Resolves Threads
I'm not done though, reverting the bale to a separate class makes me want to try learning something, if I can't work it out then no more commits
2025-06-05 20:10:20 +10:00
dhi_holo 969b070300 Very minor fix to kings rock model 2025-06-05 20:02:51 +10:00
Polymeta e474ef607c Ignore vitalspirit activation message
Closes #1595

Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-06-04 14:29:24 +01:00
Polymeta a2ecccfac4 Merge branch 'Saccharine-Tree-Bee-Nest-Orientation-Fix' into 'main'
Saccharine tree bee nest orientation fix

See merge request cable-mc/cobblemon!1695
2025-06-04 13:15:39 +00:00
Polymeta 1a475bff87 fix two mons using old behaviour keys
Closes #1598

Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-06-04 13:43:43 +01:00
Polymeta 8b6f5f55e6 Merge branch 'RaftsAndFlyingForSmartererPokemon' into 'main'
Battle flight migrated to brains, fixed illusion mobility for brains, fixed...

Closes #1496

See merge request cable-mc/cobblemon!1696
2025-06-04 10:43:47 +00:00
Polymeta 39ed65e8ca Merge branch 'main' into 'RaftsAndFlyingForSmartererPokemon'
# Conflicts:
#   common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/PokemonEntity.kt
2025-06-04 10:43:06 +00:00
dhi_holo 35dab86ef4 Kings Rock Model Switch
Changing to the original model, rather than the newer one that causes more problems
2025-06-04 20:27:14 +10:00
dhi_holo 2cc14d26b1 leftover files
damn refactors missed a bit
2025-06-04 18:31:31 +10:00
dhi_holo c29da11541 Modern Major General
I prefer `general` as a term for block classes that exist to be a baseline for many blocks (in theory) to `varied`, so swapping that over
2025-06-04 18:29:08 +10:00
dhi_holo 8188ce0ed2 The Beningging
Refactoring some stuff to simplify down
2025-06-04 18:22:28 +10:00
JazzMcNade 301de140e3 canStandOnFluid now looks at the exposed form of the pokemon 2025-06-03 23:26:32 -05:00
dhi_holo 4a41060533 Merge branch 'main' into mechanical-hands 2025-06-04 09:36:07 +10:00
Polymeta ac55636c51 small recipe fix for loaded dice
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-06-03 23:31:49 +01:00
Polymeta 18eb50d4d2 Merge branch 'data-driven-brewing' into 'main'
Wrapped the Brewing Stand to allow Data Driven Recipes

See merge request cable-mc/cobblemon!1667
2025-06-03 13:22:44 +00:00
Aram 87276de14d Update CHANGELOG.md 2025-06-03 14:42:22 +02:00
Aram b7dc9ea6f6 Removed Unneccerry files 2025-06-03 14:30:34 +02:00
Aram ff59604526 Merge branch 'main' into data-driven-brewing 2025-06-03 14:27:40 +02:00
Polymeta b620ad27b6 rename OmniPathingEntity#isOnGround > entityOnGround to get around yarn mapping conflict
Fixes #1590

Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-06-03 11:32:28 +01:00
dhi_holo 78daec9c7b Merge branch 'main' into mechanical-hands 2025-06-03 17:50:15 +10:00
Polymeta 5565f22610 Merge branch 'hyper_trained_ivs' into 'main'
Hyper Training Event and MoLang Functions

See merge request cable-mc/cobblemon!1689
2025-06-03 06:22:07 +00:00
Konoha DandPolymeta 7582b08d56 Hyper Training Event and MoLang Functions 2025-06-03 06:22:07 +00:00
Polymeta 2e101f023f Merge branch 'cleanup' into 'main'
Crash Fix

See merge request cable-mc/cobblemon!1697
2025-06-03 06:19:26 +00:00
dhi_holo d98cccfc0f Edit evolution_items.json 2025-06-03 16:12:46 +10:00
dhi_holo 07f087c35c Merge branch 'cleanup' into mechanical-hands 2025-06-03 14:39:02 +10:00
dhi_holo f83bde399c no crash
Removed some duplicates
2025-06-03 14:20:32 +10:00
dhi_holo 19f0bc29f4 Merge branch 'main' into mechanical-hands 2025-06-03 11:38:31 +10:00
dhi_holo 531f64394a Name Change Part 1
We know what they are now, what the series is called is still to be determined
2025-06-03 11:38:13 +10:00
JazzMcNade af77534b96 Removed escaped quotation marks 2025-06-02 20:01:30 -05:00
Karl Martin fa5193a3db Fix for bee nest entrances being blocked on saccharine trees 2025-06-02 22:06:10 +01:00
Polymeta e3c95aa4a5 Merge branch 'cooking-redstone' into 'main'
A ton of Redstone Compatibility inside the Cooking System

See merge request cable-mc/cobblemon!1640
2025-06-02 13:57:10 +00:00
AramandPolymeta 72740fb418 A ton of Redstone Compatibility inside the Cooking System 2025-06-02 13:57:10 +00:00
Paul 250f9e3cec Cleanup 2025-06-02 20:15:03 +10:00
Paul 26078ec29d Merge remote-tracking branch 'origin/main' 2025-06-02 20:09:11 +10:00
Paul 5b68889689 Fixed non-walking fliers not being able to wander 2025-06-02 20:09:00 +10:00
Paul bb3e86ac02 Fixed wander not being added to flying non-walkers 2025-06-02 20:08:21 +10:00
Polymeta b96a6282d8 Merge branch 'implement_pokemon' into 'main'
Fruity Implementation Merge to Main

See merge request cable-mc/cobblemon!1691
2025-06-02 08:18:00 +00:00
Frank The FarmerandPolymeta 14ee3cd754 Fruity Implementation Merge to Main 2025-06-02 08:17:59 +00:00
Paul 9c66c65b9e Merge remote-tracking branch 'origin/main' 2025-06-02 16:06:13 +10:00
Paul 9ffbd14a81 The wiki says it's called "artificial" 2025-06-02 16:06:03 +10:00
dhi_holo 7044cb35b2 jsons go grrr 2025-06-02 14:08:29 +10:00
dhi_holo e258d6439f Tops and Recipes 2025-06-02 13:53:06 +10:00
dhi_holo 221e51b023 Drops and Spin
Containers drop, fridge faces properly, new fridge texture
2025-06-02 12:20:29 +10:00
JazzMcNade 5053c765fb Merge branch 'main' into RaftsAndFlyingForSmartererPokemon 2025-06-01 17:20:39 -05:00
JazzMcNade bfe8d41102 Refactored BattleFlight as a OneShot Task, removed unnecessary memory flag. 2025-06-01 17:20:28 -05:00
dhi_holo c9fe117916 Cool
Fridge pseudo-working (visually, not functionally)
2025-06-01 21:13:20 +10:00
dhi_holo af3b6e3f2a Goes Brrr 2025-06-01 16:57:52 +10:00
dhi_holo 1b7759b77d Tweaks and fix ups 2025-06-01 13:05:09 +10:00
dhi_holo 698c07f0b8 Oven and Washer Work!
Yippee!!

They have the wrong behaviours, but it's still a major step towards these blocks being functional
2025-06-01 12:29:26 +10:00
JazzMcNade a4a094a624 spawnallpokemon no longer calls sendOut() 2025-05-31 21:29:13 -05:00
dhi_holo b0d2df2917 This was a Triumph
I'm making a note here, thank you landon.
2025-05-31 19:18:02 +10:00
dhi_holo f6ad1ab7aa what if i
blam
2025-05-31 17:50:09 +10:00
dhi_holo 3f85ce0c81 Merge branch 'main' into mechanical-hands 2025-05-30 17:13:03 +10:00
dhi_holo e25c3c3d7c Learning
Slowly trying stuff, mmmmm
2025-05-30 17:12:44 +10:00
JazzMcNade 0215a30c8d Battle flight migrated to brains, fixed illusion mobility for brains, fixed pokemon spawning with rafts outside of battle, 2025-05-30 01:17:56 -05:00
dhi_holo f16ec1d6d3 Backup
Is this me backing up my work or calling for backup? You'll never know, busy-body
2025-05-30 15:34:11 +10:00
dhi_holo 73e59159a0 Testable State again 2025-05-30 14:11:46 +10:00
dhi_holo 5b7b430e5f Data Start 2025-05-30 13:29:40 +10:00
dhi_holo 4e6f2973c2 Assets
Temporarily changed the mechanical oven to just be a regular block so that testing can be done, and added theoretically all needed assets for the appliances
2025-05-30 12:58:02 +10:00
Polymeta 4f5799e5df yet another seasoning codec tweak
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-05-30 00:39:13 +01:00
dhi_holo 822794230d Help - Kobo Kanaeru
Major Struggles, so it's time to make this not local
2025-05-30 09:26:07 +10:00
Polymeta 54ea4903ba Merge branch 'cooking-tooltip-overhaul' into 'main'
Cooking tooltip overhaul

See merge request cable-mc/cobblemon!1687
2025-05-29 22:07:13 +00:00
Plastered_CrabandPolymeta 28ad0cce83 Cooking tooltip overhaul 2025-05-29 22:07:13 +00:00
Polymeta 7fe1929609 Merge branch 'hyper_trained_ivs' into 'main'
Hyper Trained Stat IVs

See merge request cable-mc/cobblemon!1614
2025-05-29 15:53:12 +00:00
Konoha DandPolymeta e03082a75e Hyper Trained Stat IVs 2025-05-29 15:53:11 +00:00
Polymeta 8d0c27f0e4 [skip-ci] changelog
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-05-29 16:47:14 +01:00
Polymeta 91fc2dc896 Merge branch 'spawn-rules-npc-gisketch' into 'main'
Make Spawn Rules affect NPC spawns

See merge request cable-mc/cobblemon!1682
2025-05-29 15:43:12 +00:00
dhi_holo d58603ff33 Mower
No functions at all, just a model with all the needed rotation behavior and nice decoration. No data, no lang.
2025-05-29 17:01:38 +10:00
Ghegi Jimenez ab1ca295a3 Make Spawn Rules affect NPC spawns
- Update NPCSpawnDetail to have autoLabel() function similar to
  PokemonSpawnDetail to support spawn rules

Ref: https://gitlab.com/cable-mc/cobblemon/-/issues/1559
2025-05-29 09:36:37 +08:00
dhi_holo 157532f372 Merge branch 'main' into mechanical-hands 2025-05-29 11:26:05 +10:00
Polymeta 5cbe937e23 Merge branch 'tatami' into 'main'
Tatami Mats

See merge request cable-mc/cobblemon!1684
2025-05-28 09:27:00 +00:00
dhi_holoandPolymeta 4fa196da94 Tatami Mats 2025-05-28 09:27:00 +00:00
dhi_holo 3a1c3fc934 Mechanical Fan (Simple)
Implemented a Mechanical Fan. No data files, no lang translation, no bonus functions beyond being able to turn it on and off. Still needs sound events.
2025-05-28 18:26:19 +10:00
Polymeta 43aa0ec04a oop this is not needed anymore
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-05-27 00:54:28 +01:00
Polymeta b4bf044f76 small refactors in mixins and JEI integration
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-05-27 00:49:26 +01:00
Polymeta d35db46c1b Merge branch 'Add-pc-take-and-search-commands' into 'main'
Add PC Search and PC Take Commands

See merge request cable-mc/cobblemon!1677
2025-05-26 21:25:15 +00:00
Polymeta b8a6c94fcb Merge branch 'boat-behaviour' into 'main'
Add boat water behaviour

See merge request cable-mc/cobblemon!1638
2025-05-25 00:26:09 +00:00
Ghegi Jimenez b069e448c1 Add PC Search and PC Take Commands
- Add pcsearch command to search through target's PC and display pokemon info with box slots
- Add pctake command to take pokemon from target's box slot
- Pokemon are removed when using pctake on self or as server
2025-05-25 08:07:17 +08:00
Polymeta 18f41407c8 fix merge conflicts
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-05-25 00:46:35 +01:00
Polymeta b659a662a2 Merge branch 'refs/heads/main' into boat-behaviour
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/PokemonEntity.kt
2025-05-25 00:23:15 +01:00
Polymeta dbb2e45e14 Merge branch 'spicy-molang' into 'main'
Added `play_sound_on_server` and `run_molang_after` as available MoLang functions

See merge request cable-mc/cobblemon!1615
2025-05-24 23:20:14 +00:00
SpicyandPolymeta da491015a6 Added play_sound_on_server and run_molang_after as available MoLang functions 2025-05-24 23:20:14 +00:00
Polymeta 55db0d8af1 Merge branch 'battle-side-start-lang-position' into 'main'
Update battle sidestart langkeys formatting

See merge request cable-mc/cobblemon!1678
2025-05-24 23:11:38 +00:00
Ghegi Jimenez 211821bc0f Update battle sidestart langkeys formatting
This commit updates the SideStartInstruction.kt and
SideEndInstruction.kt files to use
position-specific language keys for battle side effects,
improving grammatical consistency.

**The changes**:

1. Modified SideStartInstruction.kt to use separate
language keys for ally and opponent sides

2. Updated en_us.json with new position-specific language keys
for all side effects

3. Added changelog entry documenting the improvement

This approach eliminates grammatical issues that occurred with the
previous implementation where "%1$s" was used in different positions
in sentences, making translations awkward.

The new format uses "sidestart.ally.[effect]" and
"sidestart.opponent.[effect]" keys, allowing for more natural language
in all cases.

Ref: https://gitlab.com/cable-mc/cobblemon/-/issues/984
2025-05-25 06:58:36 +08:00
Polymeta 16a21f9d2e Merge branch 'remedying-remedies' into 'main'
Remedy Rebalance

Closes #1570

See merge request cable-mc/cobblemon!1680
2025-05-24 07:46:50 +00:00
Polymeta e69060bde6 Merge branch 'fossilized-improvement' into 'main'
Fossilized Improvement (with major tangents)

Closes #1548

See merge request cable-mc/cobblemon!1673
2025-05-24 07:45:15 +00:00
dhi_holo ebdbbd5176 Indentation fixed
Looks identical to me in IntelliJ, but it's apparently different
2025-05-24 15:28:46 +10:00
dhi_holo 6e163d08f0 Merge branch 'main' into fossilized-improvement 2025-05-24 15:19:30 +10:00
dhi_holo 13c7b75b19 finished
That's the whole thing done!
2025-05-24 11:03:43 +10:00
Polymeta 1ad36e39c5 change the remedies.json layout to accommodate for individual friendshipDrops
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-05-23 23:43:58 +01:00
Polymeta f4d67b9b64 some rootblock fixes (energy root is shearable now) and energy roots run through same spreading RNG as big roots
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-05-23 22:40:16 +01:00
Polymeta 3c84afb95d Merge branch 'RestorationTankHopperFix' into 'main'
Restoration tank hopper fix

Closes #1569

See merge request cable-mc/cobblemon!1679
2025-05-23 20:43:26 +00:00
Aram 2e615800ae Update RecipeAwareSlot.java 2025-05-23 20:48:33 +02:00
JazzMcNade 0fc1239c77 Update CHANGELOG.md 2025-05-23 13:19:40 -05:00
JazzMcNade 38a0d149c5 Update RestorationTankBlockEntity.kt 2025-05-23 13:17:42 -05:00
Polymeta 4a4aaf3a94 fix mixin target for menu
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-05-23 17:03:33 +01:00
Aram 53ca8f009d Tried to Resolve getting the Level, sadly it checks twice, Server and Client, and Server is Null 2025-05-23 17:20:52 +02:00
Aram 5b5c756d3c Merge branch 'main' into data-driven-brewing 2025-05-23 14:24:38 +02:00
Aram 75410c3a72 Update BrewingStandBlockEntityMixin.java 2025-05-23 12:48:03 +02:00
Aram 87d001da80 Removed Client stuff from the server 2025-05-23 12:37:29 +02:00
dhi_holo 8fee0e7f91 Begun Rebalance
Relevant conversation: https://discord.com/channels/725110639554592879/725619428384964678/1375306792523005962

Resolves #1570 indirectly
2025-05-23 13:13:07 +10:00
dhi_holo 7985aed6bf Update en_us.json
Added the three newest tags to the lang file
2025-05-23 11:02:58 +10:00
dhi_holo 5543b8a660 Merge branch 'main' into fossilized-improvement 2025-05-23 10:45:28 +10:00
Polymeta d7d855adc2 small cleanup for structure mixin
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-05-21 14:17:06 +01:00
Hiroku 4fd50b8d2b Merge branch 'y-limit-structures' into 'main'
On request of Slippy, I created a check to make sure certain structures will not spawn below the Sea Level

See merge request cable-mc/cobblemon!1672
2025-05-21 12:28:53 +00:00
Aram be466ad252 Oops 2025-05-21 12:23:13 +02:00
Aram 53749e014b License 2025-05-21 12:22:02 +02:00
Aram b4cdf371fe It now checks for Sea Level in stead of hardcoded 65 2025-05-21 12:22:02 +02:00
Aram e0e30e7e11 Updated the Structure Check to also take StructurePieces into account 2025-05-21 12:22:02 +02:00
Aram cfec4e10cb Created a Mixin that prevents certain Structures from generating below a specific Y Level 2025-05-21 12:22:02 +02:00
Polymeta 614799cfcb Merge branch 'feature/improved-filters' into 'main'
improved filter by Name

See merge request cable-mc/cobblemon!1670
2025-05-21 09:06:34 +00:00
DavidandPolymeta ec367fd4df improved filter by Name 2025-05-21 09:06:34 +00:00
dhi_holo e415b281ee Merge branch 'main' into fossilized-improvement 2025-05-20 22:14:12 +10:00
Polymeta 265aa6e124 Merge branch 'advancing' into 'main'
forgot the optional any check

See merge request cable-mc/cobblemon!1671
2025-05-20 07:16:56 +00:00
MoeBoy76 2765a5584f forgot the optional any check 2025-05-20 14:16:29 +10:00
dhi_holo d77cb36149 Merge branch 'main' into fossilized-improvement 2025-05-20 08:37:01 +10:00
Aram d37d95ee70 Fixed the Build Error 2025-05-19 19:32:52 +02:00
Polymeta 63f8e6251e fix for wild pokemon getting jumbled up
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-05-19 11:22:49 +01:00
Polymeta 5a3e9bb236 some tidying up and fixing upper half of rice block not growing with the lower half
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-05-19 11:17:56 +01:00
dhi_holo 2fce916f05 >:D
I feel like rice isn't as good at absorbing a fall's energy, so I think this is a fun little tweak to it
2025-05-19 16:31:29 +10:00
dhi_holo 52c4c35c0d Who up Hearting they Grains
Gotta get the top half growing in sync with the bottom half (currently doesn't grow at all once it spawns in), but progress is progress
2025-05-19 15:14:44 +10:00
dhi_holo 40f4f80d6e we're graining now
hearty grains block assets all nice and pretty
2025-05-19 12:20:33 +10:00
dhi_holo 721025281f Tags+ 2025-05-18 20:31:56 +10:00
dhi_holo 08e6f68693 Merge branch 'main' into fossilized-improvement 2025-05-18 19:55:42 +10:00
dhi_holo 1e3fcf3e84 Update hearty_grains.json 2025-05-18 19:43:47 +10:00
dhi_holo 92a67ca0ca Grain Bale
Hearty Grain Bale implemented fully
2025-05-18 19:27:58 +10:00
dhi_holo 42600fc840 Graining
Attempted to improve hearty grain for the purposes of adding the assets. Top state isn't working properly, not aging, not bonemealable, etc, but it has the right state count now!
2025-05-18 16:23:13 +10:00
Polymeta 9917b57e1a fix for pokemon getting lost in the void after using /data commands on them
Closes #1551

Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-05-18 00:59:28 +01:00
dhi_holo b5e2f69207 Update candied_apple_from_cooking_pot.json
I can see things I swear
2025-05-17 18:16:08 +10:00
dhi_holo c6c83c065b Update candied_apple_from_cooking_pot.json
forgot a thing
2025-05-17 18:03:31 +10:00
dhi_holo 687381dc1b Stick it to the fruit
Candied Apples and Berries are now held by their sticks
2025-05-17 17:23:39 +10:00
dhi_holo f088dd62bc Bands (plus tweak)
Focus, Choice, and Muscle Bands now use an optimised model and new textures, and EXP Share animated texture is now a bit stronger
2025-05-17 16:45:57 +10:00
dhi_holo 3d1f9458f6 Campfire Pot Recipies
I dislike how these items are named but I'm not about to go around dealing with renaming them to the standard format of `COLOUR_campfire_pot`
2025-05-17 13:46:40 +10:00
dhi_holo 470d3807f1 Wearable Upgrades
Glasses, EXP Share, and Rocky Helmet improved upon
2025-05-17 13:35:53 +10:00
Polymeta 1c74d498e6 Merge branch 'full_bellies_1.6' into 'main'
Full bellies 1.6 branch merge

See merge request cable-mc/cobblemon!1663
2025-05-16 20:38:57 +00:00
Polymeta 4d3c46acc4 smol cleanup and prevent remove double sounds in battleApply
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-05-16 21:26:17 +01:00
Plastered_Crab fbec87d2e0 Teehee whoopsies 2025-05-16 12:25:07 -07:00
Plastered_Crab 397f8db5a0 Can feed when in battle and still affect Fullness 2025-05-16 12:21:23 -07:00
Plastered_Crab 36cd5f3894 Merge remote-tracking branch 'origin/data-driven-brewing' into data-driven-brewing 2025-05-16 10:05:17 -07:00
Plastered_Crab b86f08b069 Merge branch 'main' into data-driven-brewing
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonRecipeCategories.kt
2025-05-16 10:04:03 -07:00
Polymeta 026897719d Merge branch 'cooking-pot-recipes' into 'main'
We somehow forgot to add recipes to craft the campfire pot.... Now people can!

See merge request cable-mc/cobblemon!1669
2025-05-16 16:05:57 +00:00
Polymeta c4451ffb4f cleanup and licenses
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-05-16 17:04:58 +01:00
Plastered_Crab 710b6404e7 We somehow forgot to add recipes to craft the campfire pot.... Now people testing this in survival can do so. 2025-05-16 08:31:45 -07:00
Polymeta b8f59110f0 properly detect tags inside entity.find_nearby_block molang
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-05-16 16:04:45 +01:00
plastered_crab 75927fc1a9 licenses 2025-05-16 06:34:03 -07:00
Polymeta 0a0c1edffc Merge branch 'cooking-pot-recipe-category-tweak' into 'main'
Tweaks to Category names of recipes that accept Seasoning data + tab icons

See merge request cable-mc/cobblemon!1668
2025-05-16 09:20:35 +00:00
plastered_crab 18403c833d Merge remote-tracking branch 'origin/full_bellies_1.6' into full_bellies_1.6 2025-05-16 00:07:50 -07:00
plastered_crab b9824e5708 Remove redundant coerce 2025-05-15 23:30:11 -07:00
dhi_holo 57c1201ad0 a p p l e (and tagging)
Improved tagging for a couple things, made Candied Apples able to leave Leftovers
2025-05-16 15:18:10 +10:00
dhi_holo 4637bef5d2 Recipes and Tabs
Revised type boosting item recipes, and added some cooking items to relevant creative tabs
2025-05-16 14:19:30 +10:00
Plastered_Crab 37e0030d08 Tweaks to Category names of recipes that accept Seasoning data as well as Category icons for each tab 2025-05-15 18:56:54 -07:00
Aram 628db514b3 Fixed JEI With Data Driven Brewing Stand Recipe 2025-05-16 03:29:44 +02:00
dhi_holo 6207a01ae3 Merge branch 'main' into fossilized-improvement 2025-05-16 10:49:21 +10:00
Aram 9046217867 Fixed the Recipe + Shift Clicking Items 2025-05-16 02:07:44 +02:00
Plastered_Crab 40aaef68f9 Fixes for full bellies MR 2025-05-15 15:49:18 -07:00
Aram 09c7bd8e61 Added Last Recipe 2025-05-15 23:43:26 +02:00
Aram 8df8cb9cfe Added All Recipe 2025-05-15 23:38:52 +02:00
Aram c048e5752b Updated Recipes to allow Tags AND Item IDs 2025-05-15 23:33:57 +02:00
Aram e8aa06d633 Update super_potion_brewing_stand.json 2025-05-15 22:16:23 +02:00
Aram 64979ff742 Merge branch 'main' into data-driven-brewing 2025-05-15 22:14:55 +02:00
Aram 0163619e87 Made Potion Brewing Recipes, gotta get the Tags from Main 2025-05-15 22:14:48 +02:00
Aram 258ffd25ea Nuked the old Brewing Stand code, time to Refactor 2025-05-15 21:47:52 +02:00
Polymeta 2dd0d3dcf1 Merge branch 'cooking-recipe-overhaul' into 'main'
Vera's Crafting and Cooking recipe overhaul (with some fixes)

See merge request cable-mc/cobblemon!1665
2025-05-15 19:34:43 +00:00
Plastered_Crab cc5b65a1dd Fix some things 2025-05-15 12:33:38 -07:00
Aram b7de250457 Merge branch 'data-mixin-brewing' into 'data-driven-brewing'
Rewrote Data Driven to Mixin

See merge request cable-mc/cobblemon!1666
2025-05-15 21:12:46 +02:00
Aram 8d0c5bc05c Rewrote Data Driven to Mixin 2025-05-15 21:12:45 +02:00
plastered_crab f4e242a270 clean up some todos and CobblemonItems a bit 2025-05-15 10:15:14 -07:00
plastered_crab da3a513905 Merge remote-tracking branch 'origin/cooking-recipe-overhaul' into cooking-recipe-overhaul 2025-05-15 09:39:33 -07:00
plastered_crab 33af6a1557 Fixing Shapeless Recipes not detecting multiple of a single item 2025-05-15 09:39:18 -07:00
dhi_holo 62b07f7f8a whoopsies
typos revoked
2025-05-15 23:35:22 +10:00
dhi_holo 7bddbcfc67 YAY! MURDAH!
Removed unneeded recipes, fixed ordering in the rabbit stew recipe, fixed broken zinc recipe
2025-05-15 23:06:09 +10:00
dhi_holo 993c7a5cf0 Recipe Advancements
Added advancements for all Campfire Pot recipes, to make them unlockable during gameplay
Began cleaning up now redundant recipes/advancements due to cooking pot overwriting older recipes
2025-05-15 22:25:31 +10:00
dhi_holo 44da19f3e0 Translations Added
Tags added, and new foods that I'm fairly sure don't have translation strings elsewhere (if I'm wrong that can be fixed later, only ones I think are at risk are candied apple and fried rice)
2025-05-15 20:21:32 +10:00
dhi_holo 6d97c6ea34 Update rabbit_stew_from_cooking_pot.json
Removed unnecessary bowl from recipe (mushroom stew bowl gets consumed in the cook)
2025-05-15 19:44:00 +10:00
plastered_crab 2a55ef114d Regional Foods starting to work! 2025-05-15 01:49:40 -07:00
plastered_crab c236d8147a MORE MORE MORE changes to cooking recipes >:D 2025-05-14 23:54:38 -07:00
dhi_holo cf90bf0b0f Pots!
+ Allowed all 7 Apricorn Sprouts and Saccharine Sapling to be put in Flower Pots
+ Added all 9 of our potted blocks to the `#minecraft:flower_pots` block tag
+ Minor fix to the Potted Pep-Up Flower loot table
+ Fixed the texture name for Pep-Up Flower block
2025-05-15 16:44:34 +10:00
dhi_holo b109ff6edf Merge branch 'main' into fossilized-improvement 2025-05-15 14:45:42 +10:00
plastered_crab 4ea288cc34 MORE changes to cooking recipes >:D 2025-05-14 19:08:23 -07:00
plastered_crab 98540294b1 Start of big rework to all cooking recipes >:D 2025-05-14 16:20:52 -07:00
Polymeta 5535a6a7cb Merge branch 'cooking-fixes' into 'main'
Fixes for merged bait effects and Flavor tooltips showing on every item

See merge request cable-mc/cobblemon!1664
2025-05-14 22:00:01 +00:00
plastered_crab dd426423a1 Remove Mild flavor on tooltips 2025-05-14 12:29:56 -07:00
plastered_crab 6237e44e7c Fix Seasoning tooltip showing on every item 2025-05-14 12:08:32 -07:00
plastered_crab 09561f736a Rarity Bucket tiers can stack (with diminished returns) 2025-05-14 11:53:21 -07:00
plastered_crab 14e4fe66ac Add new item tags 2025-05-13 20:20:33 -07:00
plastered_crab 975c68cea0 Add new item tags 2025-05-13 20:17:44 -07:00
plastered_crab 6b77adbcef Remove Milking stuff to new branch, metabolism gets ticked from Party and Pasture 2025-05-13 19:55:40 -07:00
plastered_crab d12a8704a9 Merge branch 'refs/heads/main' into full_bellies_1.6 2025-05-13 17:48:48 -07:00
Apion 52fc6b2575 Merge branch 'Lure-Cake-Crash-Fix' into 'main'
Lure cake crash fix

See merge request cable-mc/cobblemon!1662
2025-05-14 00:42:12 +00:00
Plastered_CrabandApion 68ffe0bdbc Lure cake crash fix 2025-05-14 00:42:12 +00:00
Plastered_Crab 4734c0a3cb Changes to Shuckle giving berry juice 2025-05-13 14:28:29 -07:00
Aram 1ed4d9ff9a Shift Clicking items into the brewing stand is almost perfect! 2025-05-13 21:07:24 +02:00
Aram 8d0fc77be2 Update BrewingStandBlockMixin.java 2025-05-13 20:42:59 +02:00
Aram c45ef65645 Hard Coded Recipes still work to remain compatible with mods 2025-05-13 20:30:40 +02:00
Aram 0adfc64e35 DATAPACK BREWING STAND RECIPE HERE WE GO 2025-05-13 19:56:12 +02:00
Aram 80b4238c7e DATA DRIVEN RECIPE IN BREWING STAND 2025-05-13 19:55:55 +02:00
Plastered_Crab e16ae2544c Fix sounds on fullness branch 2025-05-13 10:05:21 -07:00
Aram f182cf4335 Update CobblemonRecipeCategories.kt 2025-05-13 17:38:51 +02:00
Aram f5840c4794 Nuked the Recipe Book 2025-05-13 17:38:45 +02:00
Plastered_Crab cff65ab22e Merge branch 'main' into full_bellies_1.6 2025-05-13 08:33:15 -07:00
Polymeta 1d550b2cac mixin cleanup
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-05-13 16:27:07 +01:00
Polymeta c859cbae76 small seasoning codec change to fix errors when logging into servers
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-05-13 16:26:35 +01:00
Aram 10e7962d85 Merge branch 'main' into data-driven-brewing 2025-05-13 14:39:59 +02:00
Polymeta 767f820b7a Merge branch 'food-fix' into 'main'
Allow for Food and Mob effects to be optional (fixes crash)

See merge request cable-mc/cobblemon!1661
2025-05-13 06:19:57 +00:00
dhi_holo 06e4783f16 Update resurrect_pokemon.json 2025-05-13 16:11:40 +10:00
dhi_holo fe83b9d58e Merge branch 'main' into fossilized-improvement 2025-05-13 13:26:11 +10:00
Plastered_Crab 709e6f4a63 Allow for Food and Mob effects to be optional 2025-05-12 17:13:56 -07:00
Plastered_Crab 17f686488e Added fullness values to new Poke Foods 2025-05-12 16:52:17 -07:00
Plastered_Crab db574332e5 Merge branch 'main' into full_bellies_1.6 2025-05-12 15:55:10 -07:00
Nick 73b72ff19d Merge branch 'ponigiri' into 'main'
Adds Ponigiri, Poke Puffs, Sinister Tea, and berry data changes and tool tip changes

See merge request cable-mc/cobblemon!1658
2025-05-12 15:22:58 -07:00
Plastered_CrabandNick 15aac5e20a Adds Ponigiri, Poke Puffs, Sinister Tea, and berry data changes and tool tip changes 2025-05-12 15:22:58 -07:00
Plastered_Crab b88f4335ee Fullness now saves on exit and displays in Summary "Other" menu 2025-05-12 15:08:39 -07:00
Polymeta 6916cd51f7 Merge branch 'feature/datapack-starters' into 'main'
Add datapack-driven starter menu categories

See merge request cable-mc/cobblemon!1653
2025-05-12 12:11:37 +00:00
Winter b2ebfcc3b0 Simplify category validation 2025-05-12 12:15:13 +01:00
Hiroku 3b73493801 Merge branch 'spawning-upgrades' into 'main'
Major spawning revamp with herds and rapid spawning and refactored spawn terms

See merge request cable-mc/cobblemon!1634
2025-05-11 10:29:42 +00:00
Polymeta bfb48e8583 Merge branch 'particle-fixes' into 'main'
Particle fixes

See merge request cable-mc/cobblemon!1660
2025-05-11 09:14:23 +00:00
plastered_crab 1bfe5e2044 Fix Item Tags after merge 2025-05-10 23:33:40 -07:00
plastered_crab ace65eda66 Merge branch 'refs/heads/main' into full_bellies_1.6
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/Cobblemon.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonSounds.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/tags/CobblemonItemTags.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/item/berry/FriendshipRaisingBerryItem.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/item/berry/HealingBerryItem.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/item/berry/PortionHealingBerryItem.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/item/berry/StatusCuringBerryItem.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/item/interactive/BerryJuiceItem.kt
#	common/src/main/resources/assets/cobblemon/lang/en_us.json
#	common/src/main/resources/assets/cobblemon/sounds.json
2025-05-10 22:44:39 -07:00
Apion 01c44537d0 Fix naked Gastly 2025-05-10 22:56:16 -04:00
Hiroku e414dd94c3 Merge branch 'main' into 'spawning-upgrades'
# Conflicts:
#   common/src/main/kotlin/com/cobblemon/mod/common/api/spawning/condition/SpawningCondition.kt
2025-05-11 02:34:59 +00:00
Apion 2d4800a733 Fix issue where locator X axis was not aligned with blockbench. 2025-05-10 21:50:52 -04:00
Paul 90e193e5a0 Added more information about what was renamed in spawning system 2025-05-11 10:33:18 +10:00
Hiroku c7e86cf767 Merge branch 'fix-dimension-condition' into 'main'
Fixes dimension condition using the wrong ResourceLocation.

See merge request cable-mc/cobblemon!1659
2025-05-11 00:20:00 +00:00
Paul d8906992a3 Scraper for spawns now exports 'spawnablePositionType' instead of 'context' which is the modern name 2025-05-11 10:18:33 +10:00
Neovitalism 972c259f6d changelog so hiro doesn't send a guy to break my legs 2025-05-10 19:17:46 -05:00
Paul 8228424191 Merge remote-tracking branch 'origin/spawning-upgrades' into spawning-upgrades 2025-05-11 10:14:03 +10:00
Paul 9bb67087b3 Merge remote-tracking branch 'origin/main' into spawning-upgrades 2025-05-11 10:11:25 +10:00
Neovitalism 0f08446732 Moves the imports back 2025-05-10 19:03:53 -05:00
Neovitalism af09a6a0c7 Fixes dimension condition using the wrong ResourceLocation 2025-05-10 18:55:14 -05:00
Winter b4d2f39c48 Remove unused StarterDataLoader import 2025-05-10 16:16:16 +01:00
Winter 1a12bbd493 Ignore unused exception 2025-05-10 00:09:45 +01:00
Winter 8a24f635cf Undo reformat 2025-05-10 00:05:43 +01:00
Winter d6e066ddcd Validate starter categories 2025-05-10 00:03:35 +01:00
Polymeta 50335135c9 Merge branch '603.5' into 'main'
Half resolved 1207, hence the branch name

See merge request cable-mc/cobblemon!1652
2025-05-09 22:48:28 +00:00
AramandPolymeta 1ee6f83a5b Half resolved 1207, hence the branch name 2025-05-09 22:48:28 +00:00
Landon e8b747a432 Merge branch 'gibber-no-crash' into 'main'
Fix dialogue gibber not being read as nullable for "artificial" and null speaker faces

See merge request cable-mc/cobblemon!1657
2025-05-09 21:44:17 +00:00
Dani Voort 8f8804f3f4 Fix dialogue gibber not being read as nullable for "artificial" and null speaker faces 2025-05-09 22:59:42 +02:00
Hiroku ef826158ce Merge branch 'spicy-spicy-molang' into 'main'
Added `labels` and `has_label` as available MoLang functions

See merge request cable-mc/cobblemon!1656
2025-05-09 03:29:17 +00:00
SpicyandHiroku d32314742d Added labels and has_label as available MoLang functions 2025-05-09 03:29:16 +00:00
Hiroku e8e0ca47dd Merge branch 'issue-#1543-fix' into 'main'
Fixed typo while saving/loading NPCEntity causes data loss

Closes #1543

See merge request cable-mc/cobblemon!1655
2025-05-08 23:23:49 +00:00
Bluedude ebcac6e782 Edit CHANGELOG.md 2025-05-08 17:28:28 +00:00
Dan 63bfa634ae Fixed typo while saving/loading NPCEntity causes data loss 2025-05-08 18:26:05 +02:00
Aram c3d482c78f Recipe Book is workingggg!!!!!!!!! 2025-05-08 17:47:43 +02:00
Winter 7ea85dbd1e Update CHANGELOG.md 2025-05-08 15:10:05 +01:00
Winter 6cdb14d2f8 Rely on JsonDataRegistry to auto register 2025-05-08 15:07:59 +01:00
Winter f041049576 Register StarterDataLoader 2025-05-08 15:07:23 +01:00
Winter e1aa6445fa Switch to JsonDataRegistry<StarterCategory> to be consistent with other registries 2025-05-08 15:06:51 +01:00
Winter f1b7ee5b9c Revert to original implementation 2025-05-08 15:03:35 +01:00
Polymeta 9ea0f7e4f8 Merge branch 'aprijuice-visual-tweaks' into 'main'
Aprijuice visual tweaks

See merge request cable-mc/cobblemon!1654
2025-05-08 08:46:51 +00:00
Plastered_CrabandPolymeta d0edd6ecbc Aprijuice visual tweaks 2025-05-08 08:46:51 +00:00
Winter 1372505486 Add license header 2025-05-07 22:46:18 +01:00
Winter a4ce4bf99b Add datapack starter categories with fallback support 2025-05-07 20:33:26 +01:00
Aram 7effc4c853 NON FUNCTIONAL: Finally added the Recipe Book, 2025-05-07 20:17:41 +02:00
Aram 4cd504126b BROKEN: Started adding the Recipe Book 2025-05-07 17:18:30 +02:00
Aram 60ee7b819c Created the Recipe 2025-05-07 12:48:06 +02:00
Aram 28548d5b19 Small rename? 2025-05-07 12:47:46 +02:00
Aram e6ec690811 Wrapped the Brewing Stand to allow Data Driven Recipes Soon!!!
Check previous commit
2025-05-07 01:42:51 +02:00
Aram dac49c2f42 Wrapped the Brewing Stand to allow Data Driven Recipes Soon!!!
Some small issues
* Right clicking Brewing stand first time converts it and wont open gui, so fix that
* The entire code is a Copy Paste of Vanilla ATM, need to start modifying the shit out of it
2025-05-07 01:41:30 +02:00
Polymeta d72dad355c Merge branch '1544' into 'main'
1544, Add Pokemon Despawner to Config!

See merge request cable-mc/cobblemon!1650
2025-05-06 16:10:27 +00:00
AramandPolymeta 40b5726c5b 1544, Add Pokemon Despawner to Config! 2025-05-06 16:10:27 +00:00
Polymeta d32aa46832 init PokemonProperties with basefriendship is none is explicitly set
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-05-06 00:00:24 +01:00
Polymeta 5068e66fa7 Merge branch 'advancing' into 'main'
corrected logic that was incorrectly checking the ResourceLocation of the species

See merge request cable-mc/cobblemon!1649
2025-05-05 09:53:56 +00:00
MoeBoy76 482b682595 corrected logic that was incorrectly checking the ResourceLocation of the species 2025-05-05 12:31:57 +10:00
Paul ffecc58979 Fixed gibber click interactions not being as intended 2025-05-04 13:17:39 +10:00
Paul eaaf2ca05c Added unset_interaction to NPC structs 2025-05-04 12:16:16 +10:00
Paul e91651553b Added set_dialogue_interaction to NPC structs 2025-05-04 12:14:32 +10:00
dhi_holo 874a5d2e8f Update CHANGELOG.md
forgot one sentence, whoopsie daisies
2025-05-03 16:37:08 +10:00
dhi_holo 70e49bbbdb More Tweaks
Eject Pack was fixed at some point, so I readded the recipe, loaded dice was tweaked, and started tweaking the consumed tags
2025-05-03 16:06:42 +10:00
dhi_holo 39fce8ca06 Cupping
Cups are now craftable for real, too, praise the drinkingssiah
2025-05-03 15:21:50 +10:00
dhi_holo d288fe46da Replace Pot Recipes
They were weird, now they're slightly less weird and feel more reasonable imo
2025-05-03 14:47:16 +10:00
dhi_holo cefc97320a Merge branch 'main' into fossilized-improvement 2025-05-03 14:38:35 +10:00
Test a2094677cd update pot cook button 2025-05-03 00:12:26 -04:00
Polymeta eae4eb5121 Merge branch 'E' into 'main'
🇪

See merge request cable-mc/cobblemon!1646
2025-05-02 08:33:44 +00:00
TestandPolymeta ed3a008515 🇪 2025-05-02 08:33:43 +00:00
Polymeta 462074ce43 Merge branch 'sketch-copy-move-fix' into 'main'
Sketch copy move fix

Closes #1503

See merge request cable-mc/cobblemon!1645
2025-05-02 08:32:33 +00:00
Polymeta d54a85aa68 Merge branch 'aprijuice-visual-tweaks' into 'main'
Aprijuice visual tweaks

See merge request cable-mc/cobblemon!1647
2025-05-02 08:32:14 +00:00
Plastered_CrabandPolymeta bf8433f6e9 Aprijuice visual tweaks 2025-05-02 08:32:13 +00:00
dhi_holo 374fc44089 Fossil Analyzer Visual Tweak
the top texture is now good
2025-05-02 18:30:30 +10:00
dhi_holo f7664a04db L-L-L-Lava
Wrong brainrot, ah well, funny achievement as it should be

Also changed the advancement icon for the galar fossils so it isn't just the same as the regular fossil resurrection advancement
2025-05-02 17:47:25 +10:00
CeeJay 51b0f768a0 looks better capitalized 2025-05-01 21:52:10 -04:00
CeeJay 106e487035 changelog for sketch fix 2025-05-01 21:51:08 -04:00
dhi_holo 2d772f5bf7 Update resurrect_galar_fossil.json
Should make one issue of the advancement no longer present, but the advancement itself doesn't work, pls fix Moe
2025-05-02 09:26:23 +10:00
dhi_holo 63af1713b9 Merge branch 'main' into fossilized-improvement 2025-05-01 15:39:28 +10:00
dhi_holo 8fecb12829 Three and a fix or two
Added Metal Alloy, Scroll of Darkness, and Scroll of Waters
Changed instances of `Hearty_Grains` to `HEARTY_GRAINS` to match conventions
Changed the Kings Rock wearable model to Gest's plane version
2025-05-01 15:15:26 +10:00
dhi_holo d0b50a1ee0 Sprites!
Clear Amulet, Grip Claw, Lagging Tail, and Luminous Moss now have sprites! Praise Vera!
2025-05-01 13:45:41 +10:00
plastered_crab 07497d653e More data, models, etc for Ponigiri 2025-04-30 19:08:44 -07:00
CeeJay 2ecbe28c87 remove extra line Fixes #1503 2025-04-30 21:48:12 -04:00
Polymeta 80112e0b70 pokemon can use flying pose again
Closes #1553
2025-05-01 00:05:38 +00:00
plastered_crab dfb28ed185 langs for Base, Frosted, Fancy, and Deluxe Poke Puffs 2025-04-30 14:54:08 -07:00
plastered_crab 0cc9a75255 Rough draft on Poke Puff tooltips 2025-04-30 12:59:14 -07:00
plastered_crab abfd718681 Poke Puffs are starting to work great now (visually) 2025-04-30 12:00:32 -07:00
plastered_crab 8271b7a979 I am so close but I must sleep 2025-04-30 01:42:12 -07:00
plastered_crab 251c2df78e tweak parent of first predicate 2025-04-29 23:03:38 -07:00
plastered_crab c03e30bd9c Test poke puff predicate stuff 2025-04-29 21:32:24 -07:00
CeeJay f776542365 regex to capture special characters along with spaces in sketch copying move 2025-04-29 23:39:41 -04:00
Plastered_Crab ecc793350a New experimental food stuff 2025-04-29 16:33:50 -07:00
Polymeta 045ca3a07f Merge branch 'sterr/silence' into 'main'
Pokemon no longer make sounds as they're being sent out and now respect silent nbt

See merge request cable-mc/cobblemon!1644
2025-04-29 16:04:25 +00:00
dhi_holo a71bad07bd One. Year. Later.
Re-enabled the commented out held items, which almost resolves #1548, as they are still awaiting textures. But, I wanted to work with jsons, so this commit was made.
I also cleaned up/improved some recipe advancement jsons to be more accurate when reasonable
2025-04-29 20:37:22 +10:00
Sterrezo 2085f12fef Pokemon no longer make sounds as they're being sent out and now respect silent nbt 2025-04-29 02:08:17 +02:00
Hiroku 863b43f902 Debug code that you never saw shush 2025-04-28 10:25:32 +00:00
Hiroku 1769af7385 Merge branch 'main' into 'boat-behaviour'
# Conflicts:
#   common/src/main/kotlin/com/cobblemon/mod/common/util/adapters/RidingBehaviourSettingsAdapter.kt
2025-04-27 08:54:17 +00:00
Landon Wills 88e38bfa1a Remove additional references to submarine behaviour 2025-04-26 11:48:09 -04:00
Landon Wills 507a9a54b5 Remove submarine behaviour 2025-04-26 11:47:20 -04:00
Landon Wills 0b72a072bd Fix merge issues 2025-04-26 11:40:44 -04:00
Landon Wills c927cae609 Merge branch 'refs/heads/main' into water-mount-behaviours
# Conflicts:
#	common/src/main/java/com/cobblemon/mod/common/mixin/client/CameraMixin.java
#	common/src/main/kotlin/com/cobblemon/mod/common/api/riding/behaviour/types/GenericSwimBehaviour.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/riding/behaviour/types/air/BirdBehaviour.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/riding/behaviour/types/air/GliderBehaviour.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/riding/behaviour/types/air/JetBehaviour.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/riding/behaviour/types/land/HorseBehaviour.kt
2025-04-26 11:21:33 -04:00
Paul 474918e414 Reimplemented lure cake nomnoms 2025-04-26 20:14:52 +10:00
Paul 0e93383c90 Fixed up saccharine honey tree spawning stuff 2025-04-26 17:41:04 +10:00
Paul abb44cf696 Testo fixo 2025-04-26 12:22:55 +10:00
Paul e6bd7cad72 Brought fishing in line with new spawning bucket normalizing 2025-04-26 11:41:19 +10:00
Paul e2db59c837 Oop fixed zone influences not being packed into contexts 2025-04-25 18:10:54 +10:00
dhi_holo 10bf69a79b Minor Ball Recipe Tweaks
Just cleans up three recipes
2025-04-25 17:11:16 +10:00
dhi_holo 172293c813 Merge branch 'main' into fossilized-improvement 2025-04-25 17:08:43 +10:00
dhi_holo 9bb653b8b7 Update resurrect_galar_fossil.json
should match upcoming clean up
2025-04-25 17:08:28 +10:00
Paul 7d06f1e2cd Major spawning revamp with herds and rapid spawning and refactored spawn terms 2025-04-25 14:39:33 +10:00
Landon Wills a7b55e5d03 Add submarine behaviour 2025-04-23 05:47:56 -04:00
Landon Wills 28db655376 Fix issues with third person camera offsets 2025-04-23 05:47:40 -04:00
Landon Wills 006736cd71 Refactor behaviour names, hook up max up step to riding controller 2025-04-23 03:09:57 -04:00
Landon Wills f240dc1963 Prevent auto step for boat behaviour 2025-04-22 10:46:20 -04:00
Landon Wills 535c5f2e67 Rename to boat behaviour 2025-04-22 09:55:39 -04:00
Landon Wills 8b209e081b Hook up skill and stamina 2025-04-22 09:29:26 -04:00
Landon Wills f7f276ecfb Clean things up, add acceleration logic 2025-04-22 08:37:32 -04:00
dhi_holo fc0cd0dac4 improvement phase 1
new advancement to trigger when reviving galar hybrid fossils, to help inform players of the combinations needed for it
It doesn't work yet, as the conditions don't actually exist, but I'm just making a commit for it to complain using
2025-04-21 07:46:41 +10:00
Landon Wills 019245472f Add riding stat calcs for jump and speed, some experimenting with fov 2025-04-20 07:55:14 -04:00
Landon Wills cefb502f10 Prevent 360 look on boat controller, add jump, add momentum logic when transitioning from forward/backwards input 2025-04-20 07:11:37 -04:00
Landon Wills ee5e4d33b2 Fix merge issues 2025-04-19 23:14:08 -04:00
Landon Wills 0fd954ffa5 Merge branch 'refs/heads/riding-debug-ui' into water-mount-behaviours 2025-04-19 23:10:49 -04:00
Landon Wills 60d3d737f9 Merge branch 'refs/heads/main' into water-mount-behaviours 2025-04-19 23:10:36 -04:00
Landon Wills 1caf963323 Start implementing boat behaviour 2025-04-14 00:43:47 -04:00
Landon Wills bb94f872a9 Fix player shrinking when riding pokemon that's getting retrieved to pokeball 2025-04-13 21:44:06 -04:00
plastered_crab 65ab0f48e4 - ported over Fullness Mechanics from 1.20.1 to 1.21 2024-07-28 15:07:39 -07:00
2154 changed files with 91872 additions and 21414 deletions
+3 -2
View File
@@ -2,8 +2,9 @@
- Rebuilt Pokémon AI to use Minecraft's Brain system, allowing for more complex behaviours and interactions.
- As an early pass of this, pastured Pokémon will now sleep when appropriate, and may come up to you when they see you.
- Probably also added a whole bunch of bugs.
- Growlithe and Arcanine intimidate Skeletons.
- Meowth intimidate Creepers and Phantoms.
- Dog Pokémon (Growlithe, Arcanine, etc.) intimidate Skeletons.
- Cat Pokémon (Meowth, Persian, etc.) intimidate Creepers and Phantoms.
- Sleep-related Pokémon (Munsharna, Komala, etc.) intimidate Phantoms.
- Added a Behaviour Editor to the NPC editing screen.
- Added /behaviouredit command for opening the Behaviour Editor on Pokémon and NPCs.
- Editing variables for Pokémon is not yet supported.
+23
View File
@@ -4,6 +4,29 @@
- There is a different pot for each apricorn colour because at this point I think we may have an addiction.
- Added Aprijuice, made from the Campfire Pot using apricorns with seasoning to give flavours.
- Aprijuice can be fed to ride-able Pokémon to improve their riding characteristics, depending on the flavour and the Pokémon's nature.
- Added Lure Cakes, made from the Campfire Pot using honey and berries.
- Lure Cakes can be used to modify the spawn rate of Pokémon in the wild.
- Added the Saccharine Tree, which can be found in the wild and is used to obtain Honey Bottles.
- The leaves of the tree can be harvested to obtain honey, which can be used in the Campfire Pot to make Lure Cakes.
- The Log of the tree can be clicked on with honey to create a Honey Log, which increases the change of spawning a Pokemon with an Hidden Ability.
- Clicking on the Progress Arrow will show the JEI Recipe Book for the Campfire Pot, which will show all recipes that can be made with it.
- Added a Ton of Redstone Compatibility.
- Dispenser can now Honey and Unhoney:
- Saccharine Log
- Saccharine Leaves
- Redstone can Close and Open the Lid of a Cooking Pot
- Powered = Closed
- Unpowered = Open
- Hoppers can be used to insert items into a Cooking pot
- Top = Seasonals
- All Sides = Crafting
- Bottom = Extract the Result
- Observer will recognise when a Cooking pot is Closed or Opened
- Comparator Calculates a Signal Strength depending on the items inside the cooking pot
- Sculk Sensor
- Saccharine Leaves
- Opening and Closing the Cooking Pot
- Saccharine Log
### Datapack and Addon Changes
- Renamed the fishing_baits datapack folder to spawn_bait_effects.
+1
View File
@@ -7,6 +7,7 @@
- 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.
- Added IVs and EVs stat displays in PC.
- improved filter by Name, now is available search by exact names or partial matches, for example "cha" will show Charmander, Charmeleon and Charizard among others that match.
### Developer
- Added `RenamePCBoxEvent.Pre` and `RenamePCBoxEvent.Post` events to prevent players from renaming a box or changing their input.
+16
View File
@@ -0,0 +1,16 @@
### Additions
- Pokémon can now spawn in herds, either as distinct herd groupings or simply several Pokémon spawning at once.
### Fixes
- Fixed the "enabled" property in spawn files not actually being respected. Where do they find these devs?
### Developer
- Spawning Influences now have the context of what the other buckets are when adjusting bucket weights. This will break existing influences that do bucket weight adjustment.
- Renamed heaps of things in the spawning system to make more sense.
- SpawningContext is now SpawnablePosition
- WorldSlice is SpawningZone
- SpawningProspector is now SpawningZoneGenerator
- Renamed things in Spawn Rules to go with the other renames:
- contextSelector is now spawnablePositionSelector
- context is now spawnable_position
+112 -4
View File
@@ -21,6 +21,15 @@
- Fixed Moon Ball moon phase logic to actually work correctly
- Added `translucent_cull` boolean option into resolver's layer to allow for translucent textures with culling
- Added [LambDynamicLights](https://modrinth.com/mod/lambdynamiclights) support for items held by Pokémon.
- Added the Clear Amulet, Grip Claw, Lagging Tail, Luminous Moss, Metal Alloy, Scroll of Darkness, Scroll of Waters
- Added Recipes for Masterpiece Cup, Eject Pack
- Added modification to Minecraft Creative Inventory search to account for item names that contain `poké` when input contains `poke`.
- Added Campfire Pot as well as loads of new food items (Poke Puffs, Ponigiri, Sinister Tea, etc)
- Added Hearty Grains, a new crop used in the new cooking mechanic
- Added Tatami blocks and Tatami Mat blocks, made from Hearty Grain, for decorating builds
- Added `/pcsearch <player> <pokemonProperties>` command that searches for a specific Pokémon within a player's PC.
- Added `/pctake <player> <box> <slot>` command that takes a specific Pokémon from a player's PC. Removes the pokemon if target is self or ran from the server.
- Added Hyper Training items (IV Modification) as well as some additional candy items to do so (Health Candy, Sickly Candy)
### Pokémon Added
@@ -32,12 +41,17 @@
- Grumpig
- Snorunt
- Glalie
- Latias
- Latios
#### Gen 4
- Bronzor
- Bronzong
- Croagunk
- Toxicroak
- Froslass
- Glameow
- Purugly
#### Gen 5
- Pansage
@@ -50,10 +64,22 @@
- Musharna
- Blitzle
- Zebstrika
- Drilbur
- Excadrill
- Trubbish
- Garbodor
- Gothita
- Gothorita
- Gothitelle
- Solosis
- Duosion
- Reuniclus
#### Gen 6
- Inkay
- Malamar
- Hawlucha
- Dedenne
- Noibat
- Noivern
@@ -63,13 +89,20 @@
#### Gen 8
- Silicobra
- Sandaconda
- Sinistea
- Polteageist
#### Gen 9
- Smoliv
- Dolliv
- Arboliva
- Tarountula
- Spidops
- Orthworm
- Dudunsparce
- Cyclizar
- Poltchageist
- Sinistcha
### Animation updates for the following Pokémon
- Garchomp
@@ -82,6 +115,15 @@
- Delphox
- Cinderace
- Kangaskhan
- Gossifleur
- Eldegoss
- Stonjourner
- Wailmer
- Lechonk
- Oinkologne
- Dratini
- Dragonair
- Dragonite
### Model updates for the following Pokémon
- Gyarados
@@ -99,27 +141,52 @@
- Grovyle
- Sceptile
- Honchkrow
- Gible
- Gabite
- Garchomp
- Pidgeot
- Nosepass
- Probopass
- Kangaskhan
- Cinderace
- Magnemite
- Magneton
- Magnezone
- Beldum
- Metang
- Metagross
- Hoothoot
- Noctowl
- Teddiursa
- Ursaring
- Ursaluna
- Heatmor
- Bouffalant
- Sigilyph
- Sharpedo
- Maractus
- Clodsire
- Scyther
- Scizor
- Cacturne
- Taillow
- Swellow
- Added Syrupy Apples.
- Seel
- Dewgong
### Changes
- Renamed `chargeGainedPerTick` config to `secondsToChargeHealingMachine`.
- Made Blocks of Gold count as Big Nuggets when held by a Pokémon (for Fling functionality)
- Players can now eat Sweet and Tart Apples, Whipped Dreams, and the Alcremie Sweets.
- Updated Sweet and Tart Apple sprites
- Updated the following recipes: Air Balloon, Assault Vest, Binding Band, Black Belt, Blunder Policy, Choice Band, Choice Scarf, Cleanse Tag, Covert Cloak, Destiny Knot, Eject Button, Expert Belt, Focus Band, Focus Sash, Magnet, Metronome, Muscle Band, Power Anklet, Power Band, Power Belt, Power Bracer, Power Lens, Power Weight, Protective Pads, Protein, Punching Glove, Reaper Cloth, Rocky Helmet, Room Service, Sachet, Safety Goggles, Silk Scarf, Spell Tag, Utility Umbrella, Weakness Policy, Zinc
- Added alternate ingredient options to the following recipes: Cell Battery, Charcoal Stick, Dragon Fang, Miracle Seed, Mystic Water, Never Melt Ice, Twisted Spoon, Damp Rock, Heat Rock, Icy Rock, Smooth Rock
- Updated the following recipes: Air Balloon, Assault Vest, Binding Band, Black Belt, Blunder Policy, Choice Band, Choice Scarf, Cleanse Tag, Covert Cloak, Destiny Knot, Eject Button, Expert Belt, Focus Band, Focus Sash, Magnet, Metronome, Muscle Band, Power Anklet, Power Band, Power Belt, Power Bracer, Power Lens, Power Weight, Protective Pads, Protein, Punching Glove, Reaper Cloth, Rocky Helmet, Room Service, Sachet, Safety Goggles, Silk Scarf, Spell Tag, Utility Umbrella, Weakness Policy, Zinc, Chipped Pot, Cracked Pot, Unremarkable Cup, Loaded Dice, Charcoal Stick, Dragon Fang, Miracle Seed, Mystic Water, Never Melt Ice, Twisted Spoon, Black Glasses, Fairy Feather, Hard Stone, Silver Powder, Soft Sand
- Added alternate ingredient options to the following recipes: Cell Battery, Damp Rock, Heat Rock, Icy Rock, Smooth Rock
- Grouped together some recipes within the Recipe Book. Groups include: the seven basic Poké Balls, the seven basic Ancient Poké Balls, Gilded Chests, Pokedexes, and the Weather Rocks.
- Updated some item tags to better integrate behaviours between Cobblemon, Vanilla Minecraft, and other mods
- Removed Cooked Meat, Raw Meat, Protein Ingredients, and Zinc Ingredients, the first two are now using `c` namespace tags, the latter have better integrated use of tags within their recipes which removes need for custom tags.
- Added our seeds tag into `#c:seeds`, which is now made use of for the Miracle Seed recipe.
- Added our seeds tag into `#c:seeds`, which is now made use of for the Miracle Seed recipe.
- Added herbs and snowballs to the consumable in PvE and Wild battle tags
- Tweaked the Natural Materials Vanilla file to fit with the changes to tags
- Substantially optimised spawning checks mainly by front-loading biome filtering.
- When using the `cobblemon` or `generation_9` capture calculators a critical capture with a single shake will always play for successful captures when you've already registered the Pokémon as caught in your Pokédex.
@@ -134,8 +201,18 @@
- Improved parity with vanilla mobs' drop behavior; loot and XP drop on death instead of after the entire death sequence finishes.
- Quirk animations no longer play in the battle GUI since they were pretty distracting.
- A number of Pokemon that float above the ground visually (Gastly, Klingklang, etc.) are no longer considered to be touching the ground
- Changed the recipes for Level, Lure, and Moon Balls to be cleaner
- Renamed `pokemonId` and `type` to `species` in relevant Advancement triggers for conformity, this is a breaking change.
- Added a separate `species` argument to the `pick_starter`, `pasture_use` and `resurrect_pokemon` Advancement triggers.
- Made `CobblemonAgingDespawner` thresholds configurable via the config file.
- Tweaked Berry flavor data to balance cooking pot mechanics
- Made Red, Yellow, Green, Blue, Pink, Black, and White Apricorn Sprout and Saccharine Sapling able to be placed into flower pots.
- Added all Potted Apricorn Sprouts, Potted Saccharine Saplings, and Potted Pep-Up Flowers to the `#minecraft:flower_pots` block tag
- Corrected the healing values of the remedies and energy root, and reintroduced the friendship lowering mechanics for them, revivl herb, and heal powder
- Updated battle language keys for side effects to use position-specific formats, improving grammatical consistency
- Saccharine Leaves are now Collectable
- Saccharine Leaves Age 1 or higher will now show Yellow particles when broken
- Destroying a Saccharine Honey Log will now drop a Saccharine Log in stead of nothing
### Fixes
- Fixed Particles sometimes facing the wrong direction (looking at you, Swords Dance)
@@ -169,6 +246,23 @@
- Fixed dragon's breath not being usable on the restoration tank when it should be
- Fixed Moon Stones not interacting properly with dripstone blocks.
- Fixed some effects like particles from fishing rods appearing for players in the same coordinates in another world.
- Fixed an issue with Sketch where the Pokémon using Sketch would not properly learn moves with special characters in their name (e.g. King's Shield, Baby-Doll Eyes, etc.)
- Fixed wild Pokémon sometimes spawning with incorrect friendship values
- Fixed typo while saving/loading NPCEntity causes data loss
- Fixed an issue where catching a Pokémon while it was leashed to a fence would not update the fence.
- Fixed the `dimensions` spawning condition using the incorrect ResourceLocation, causing it to not function properly.
- Fix issue where locator X axis was not aligned with blockbench.
- Fix issue where particle effects that play on frame 1 on sendout would never play (Gastly)
- The Wiglett line will now sink in water again.
- Fixed the Sprigatito line's portraits being zoomed in too far.
- Fixed Floragato's battle cry animation from breaking.
- Fixed the block texture name for the Pep-Up Flower being inaccurate
- Fixed issue where the restoration tank would not accept valid items from a hopper.
- Fixed energy root not being shearable
- Fixed energy root always spreading into more energy roots instead of by chance (same as big root)
- Fixed issue where Pokémon spawned by the "spawnallpokemon" command potentially receiving a raft.
- Fixed logspam on NeoForge when adorn is not installed
- Fixed Cobblemon crashing if it tries to load a bedrock model not meant for cobblemon (example: Qlipoth Awakening)
### Developer
- A finished battle now has winners and losers set inside of `PokemonBattle` instead of them always being empty.
@@ -195,6 +289,10 @@
}
}
`
- The IVs class has now been extended to include Hyper Trained values.
- Added `Pokemon#hyperTrainIV()` and `IVs#setHyperTrainedIV(Stat, Int)`.
- Added `HyperTrainedIvEvent.Pre` and `HyperTrainedIvEvent.Post`.
- Added a `hoverText` option to PartySelectCallback, to display a tooltip on hovering over a Pokémon in the selection screen.
### 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)
@@ -214,6 +312,15 @@
- Fixed `heldItem` property inside spawn files not working and causing crashes
- Fixed `spawn_bedrock_particles` MoLang causing crashes when used in a server environment
- The Pokédex form lang key definition now follows `cobblemon.ui.pokedex.info.form.{species}-{formname}` instead of `cobblemon.ui.pokedex.info.form.{formname}`.
- Added `play_sound_on_server` as an available Molang function for the `worldHolder` & `player` functions.
- Added `run_molang_after` as an available Molang function for the `entity` functions when schedulable.
- Added an optional parameter for `run_molang` to schedule the function.
- Added `labels` & `has_label` as available Molang functions for the `speciesFunctions`
- Added datapack-defined starter categories via `data/<namespace>/starters/*.json`, with built-in fallback and `useConfigStarters` merge option.
- The format of the `remedies.json` file has changed to allow for individual friendshipDrop amounts per remedy
- Fixed `entity.find_nearby_block` causing crashes when attempting to use a block tag
- Spawn Filters can now access `v.spawn.class` to get the identifier of an NPC class for when trying to influence NPC spawns
- Added `pokemon.hyper_train_iv` as an available Molang function.
## [1.6.1 (January 26th, 2025)](#1-6-1)
@@ -1028,6 +1135,7 @@
}
`
- Added support for custom stashes, similar to Gimmighoul's coin and scrap stashes.
- Added the ability to create custom brewing stand recipes.
### Localization
- Updated translations for:
@@ -2335,4 +2443,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.
@@ -6,3 +6,10 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.duck;
import net.minecraft.world.item.crafting.RecipeManager;
public interface RecipeAwareSlot {
void setRecipeManager(RecipeManager recipeManager);
}
@@ -1,119 +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.OrientationControllable;
import com.cobblemon.mod.common.api.orientation.OrientationController;
import com.cobblemon.mod.common.api.riding.Seat;
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate;
import com.cobblemon.mod.common.client.render.MatrixWrapper;
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState;
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel;
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.mojang.authlib.GameProfile;
import net.minecraft.client.CameraType;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
import org.joml.Matrix3f;
import org.joml.Vector3f;
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.CallbackInfoReturnable;
import java.util.Map;
@Mixin(LocalPlayer.class)
public abstract class LocalPlayerMixin extends AbstractClientPlayer implements OrientationControllable {
@Shadow
private float jumpRidingScale;
public LocalPlayerMixin(ClientLevel clientLevel, GameProfile gameProfile) {
super(clientLevel, gameProfile);
}
@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) {
var rideValue = pokemonEntity.<Float>ifRidingAvailableSupply(null, (behaviour, settings, state) -> {
if (behaviour.canJump(settings, state, pokemonEntity, player)) return null;
return behaviour.setRideBar(settings, state, pokemonEntity, player);
});
if (rideValue != null) {
cir.setReturnValue(rideValue);
}
}
}
@Override
public HitResult pick(double hitDistance, float partialTicks, boolean hitFluids) {
Entity vehicle = this.getVehicle();
if (vehicle instanceof PokemonEntity pokemonEntity) {
int seatIndex = pokemonEntity.getPassengers().indexOf(this);
Seat seat = pokemonEntity.getSeats().get(seatIndex);
PokemonClientDelegate delegate = (PokemonClientDelegate) pokemonEntity.getDelegate();
MatrixWrapper locator = delegate.getLocatorStates().get(seat.getLocator());
if (locator == null) {
super.pick(hitDistance, partialTicks, hitFluids);
}
Vec3 locatorOffset = new Vec3(locator.getMatrix().getTranslation(new Vector3f()));
OrientationController controller = this.getOrientationController();
float currEyeHeight = this.getEyeHeight();
Vector3f offset = new Vector3f(new Vector3f(0f, currEyeHeight - (this.getBbHeight() / 2), 0f));
if (Minecraft.getInstance().options.getCameraType() == CameraType.FIRST_PERSON) {
PosableModel model = VaryingModelRepository.INSTANCE.getPoser(pokemonEntity.getPokemon().getSpecies().getResourceIdentifier(), new FloatingState());
offset.add(cobblemon$getFirstPersonOffset(model, seat));
}
Matrix3f orientation = controller.isActive() && controller.getOrientation() != null ? controller.getOrientation() : new Matrix3f();
Vec3 rotatedEyeHeight = new Vec3(orientation.transform(offset));
Vec3 eyePosition = locatorOffset.add(pokemonEntity.position()).add(rotatedEyeHeight);
Vec3 viewVector = this.getViewVector(partialTicks);
Vec3 viewDistanceVector = eyePosition.add(viewVector.x * hitDistance, viewVector.y * hitDistance, viewVector.z * hitDistance);
return this.level()
.clip(
new ClipContext(
eyePosition, viewDistanceVector, ClipContext.Block.OUTLINE, hitFluids ? net.minecraft.world.level.ClipContext.Fluid.ANY : net.minecraft.world.level.ClipContext.Fluid.NONE, this
)
);
}
return super.pick(hitDistance, partialTicks, hitFluids);
}
@Unique
private static @NotNull Vector3f cobblemon$getFirstPersonOffset(PosableModel model, Seat seat) {
Map<String, Vec3> cameraOffsets = model.getFirstPersonCameraOffset();
if (cameraOffsets.containsKey(seat.getLocator())) {
return cameraOffsets.get(seat.getLocator()).toVector3f();
} else {
return new Vector3f(0f, 0f, 0f);
}
}
}
@@ -0,0 +1,67 @@
/*
* 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.world.CobblemonStructureIDs;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.core.Holder;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.levelgen.RandomState;
import net.minecraft.world.level.levelgen.structure.Structure;
import net.minecraft.world.level.levelgen.structure.StructurePiece;
import net.minecraft.world.level.levelgen.structure.StructureStart;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;
@Mixin(Structure.class)
public abstract class StructureMixin {
// Define a set of structures that should not spawn below Sea Level
@Unique
private static final Set<ResourceLocation> RESTRICTED_STRUCTURES = new HashSet<>(Arrays.asList(
CobblemonStructureIDs.STONJOURNER_HENGE,
CobblemonStructureIDs.LUNA_HENGE,
CobblemonStructureIDs.SOL_HENGE
));
@Inject(method = "generate", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/levelgen/structure/StructureStart;isValid()Z"),
cancellable = true)
public void cobblemon$isValid(RegistryAccess registryAccess, ChunkGenerator chunkGenerator, BiomeSource biomeSource,
RandomState randomState, StructureTemplateManager structureTemplateManager, long seed,
ChunkPos chunkPos, int references, LevelHeightAccessor heightAccessor,
Predicate<Holder<Biome>> validBiome,
CallbackInfoReturnable<StructureStart> cir,
@Local StructureStart structureStart) {
ResourceLocation structureKey = registryAccess.registryOrThrow(Registries.STRUCTURE).getKey((Structure) (Object) this);
if(!RESTRICTED_STRUCTURES.contains(structureKey)) {
return;
}
for (StructurePiece piece : structureStart.getPieces()) {
if (piece.getBoundingBox().minY() < chunkGenerator.getSeaLevel()) {
cir.setReturnValue(StructureStart.INVALID_START);
return;
}
}
}
}
@@ -0,0 +1,94 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.brewing;
import com.cobblemon.mod.common.CobblemonRecipeTypes;
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandInput;
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.core.BlockPos;
import net.minecraft.core.NonNullList;
import net.minecraft.world.Containers;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.alchemy.PotionBrewing;
import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.LevelEvent;
import net.minecraft.world.level.block.entity.BrewingStandBlockEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import java.util.List;
import java.util.Optional;
@Mixin(BrewingStandBlockEntity.class)
public class BrewingStandBlockEntityMixin {
@WrapOperation(method = "serverTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/BrewingStandBlockEntity;doBrew(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/core/NonNullList;)V"))
private static void cobblemon$doBrew(Level level, BlockPos pos, NonNullList<ItemStack> slots, Operation<Void> original) {
var recipe = cobblemon$fetchBrewingRecipe(slots, level);
if(recipe == null) {
original.call(level, pos, slots);
return;
}
//copied from vanilla doBrew logic, but slightly tweaked to work for cobblemon, this was needed as replacing the loop was not quite possible inside doBrew
ItemStack itemStack = slots.get(3);
for(int i = 0; i < 3; ++i) {
slots.set(i, recipe.getResult().copy());
}
itemStack.shrink(1);
if (itemStack.getItem().hasCraftingRemainingItem()) {
ItemStack itemStack2 = new ItemStack(itemStack.getItem().getCraftingRemainingItem());
if (itemStack.isEmpty()) {
itemStack = itemStack2;
} else {
Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), itemStack2);
}
}
slots.set(3, itemStack);
level.levelEvent(LevelEvent.SOUND_BREWING_STAND_BREW, pos, 0);
}
@WrapOperation(method = "serverTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/BrewingStandBlockEntity;isBrewable(Lnet/minecraft/world/item/alchemy/PotionBrewing;Lnet/minecraft/core/NonNullList;)Z"))
private static boolean cobblemon$isBrewable(PotionBrewing potionBrewing, NonNullList<ItemStack> items, Operation<Boolean> original,
@Local(argsOnly = true) Level level) {
return cobblemon$fetchBrewingRecipe(items, level) != null || original.call(potionBrewing, items);
}
@Unique
private static BrewingStandRecipe cobblemon$fetchBrewingRecipe(NonNullList<ItemStack> items, Level level) {
ItemStack ingredient = items.get(3);
List<ItemStack> bottles = items.subList(0, 3);
boolean allBottlesEmpty = true;
for (ItemStack bottle : bottles) {
if (!bottle.isEmpty()) {
allBottlesEmpty = false;
break;
}
}
if (ingredient.isEmpty() || allBottlesEmpty) {
return null;
}
BrewingStandInput input = new BrewingStandInput(ingredient, bottles);
RecipeManager recipeManager = level.getRecipeManager();
Optional<RecipeHolder<BrewingStandRecipe>> recipeHolder =
recipeManager.getRecipeFor(CobblemonRecipeTypes.INSTANCE.getBREWING_STAND(), input, level);
return recipeHolder.map(RecipeHolder::value).orElse(null);
}
}
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.brewing;
import com.cobblemon.mod.common.duck.RecipeAwareSlot;
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.world.Container;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.BrewingStandMenu;
import net.minecraft.world.inventory.ContainerData;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(BrewingStandMenu.class)
public abstract class BrewingStandMenuMixin {
@Inject(method = "<init>(ILnet/minecraft/world/entity/player/Inventory;Lnet/minecraft/world/Container;Lnet/minecraft/world/inventory/ContainerData;)V", at = @At("TAIL"))
private void captureLevel(int containerId, Inventory playerInventory, Container brewingStandContainer, ContainerData brewingStandData, CallbackInfo ci) {
var recipeManager = playerInventory.player.level().getRecipeManager();
for (Slot slot : ((BrewingStandMenu) (Object) this).slots) {
if (slot instanceof RecipeAwareSlot awareSlot) {
awareSlot.setRecipeManager(recipeManager);
}
}
}
@WrapOperation(method = "quickMoveStack", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/inventory/BrewingStandMenu$PotionSlot;mayPlaceItem(Lnet/minecraft/world/item/ItemStack;)Z"))
private boolean cobblemon$isPotionBottle(ItemStack stack, Operation<Boolean> original, @Local(argsOnly = true) Player player) {
return BrewingStandRecipe.Companion.isBottle(stack, player.level().getRecipeManager()) || original.call(stack);
}
}
@@ -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.brewing;
import com.cobblemon.mod.common.duck.RecipeAwareSlot;
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
import net.minecraft.world.inventory.BrewingStandMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(BrewingStandMenu.IngredientsSlot.class)
public class IngredientSlotMixin implements RecipeAwareSlot {
@Unique
private RecipeManager cobblemon$recipeManager;
@Override
public void setRecipeManager(RecipeManager recipeManager) {
this.cobblemon$recipeManager = recipeManager;
}
@Inject(
method = "mayPlace",
at = @At("HEAD"),
cancellable = true
)
private void cobblemon$mayPlace(ItemStack stack, CallbackInfoReturnable<Boolean> cir) {
if (BrewingStandRecipe.Companion.isInput(stack, cobblemon$recipeManager)) {
cir.setReturnValue(true);
}
}
}
@@ -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.brewing;
import com.cobblemon.mod.common.duck.RecipeAwareSlot;
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
import net.minecraft.world.inventory.BrewingStandMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(BrewingStandMenu.PotionSlot.class)
public class PotionSlotMixin implements RecipeAwareSlot {
@Unique
private RecipeManager cobblemon$recipeManager;
@Override
public void setRecipeManager(RecipeManager recipeManager) {
this.cobblemon$recipeManager = recipeManager;
}
@Inject(
method = "mayPlace",
at = @At("HEAD"),
cancellable = true
)
private void cobblemon$mayPlace(ItemStack stack, CallbackInfoReturnable<Boolean> cir) {
if (BrewingStandRecipe.Companion.isBottle(stack, cobblemon$recipeManager)) {
cir.setReturnValue(true);
}
}
}
@@ -19,7 +19,6 @@ import net.minecraft.client.ClientRecipeBook;
import net.minecraft.client.RecipeBookCategories;
import net.minecraft.client.gui.screens.recipebook.RecipeCollection;
import net.minecraft.core.RegistryAccess;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeHolder;
import org.spongepowered.asm.mixin.Mixin;
@@ -40,9 +39,11 @@ public abstract class ClientRecipeBookMixin {
return null;
}
@Shadow private Map<RecipeBookCategories, List<RecipeCollection>> collectionsByTab;
@Shadow
private Map<RecipeBookCategories, List<RecipeCollection>> collectionsByTab;
@Shadow private List<RecipeCollection> allCollections;
@Shadow
private List<RecipeCollection> allCollections;
@Inject(method = "getCategory", at = @At(value = "HEAD"), cancellable = true)
private static void addCustomCategory(RecipeHolder<?> recipe, CallbackInfoReturnable<RecipeBookCategories> cir) {
@@ -56,7 +57,7 @@ public abstract class ClientRecipeBookMixin {
case MISC -> var7 = CobblemonRecipeCategories.COOKING_POT_MISC.toVanillaCategory();
case FOODS -> var7 = CobblemonRecipeCategories.COOKING_POT_FOODS.toVanillaCategory();
case MEDICINES -> var7 = CobblemonRecipeCategories.COOKING_POT_MEDICINES.toVanillaCategory();
case BAITS -> var7 = CobblemonRecipeCategories.COOKING_POT_BAITS.toVanillaCategory();
case COMPLEX_DISHES -> var7 = CobblemonRecipeCategories.COOKING_POT_COMPLEX_DISHES.toVanillaCategory();
default -> throw new MatchException(null, null);
}
cir.setReturnValue(var7);
@@ -76,8 +77,8 @@ public abstract class ClientRecipeBookMixin {
.collect(ImmutableList.toImmutableList());
map2.put(recipeBookCategories, collections);
});
RecipeBookCategories.AGGREGATE_CATEGORIES.forEach((recipeBookCategories, list) -> map2.put(recipeBookCategories, (List)list.stream().flatMap((recipeBookCategoriesx) -> ((List)map2.getOrDefault(recipeBookCategoriesx, ImmutableList.of())).stream()).collect(ImmutableList.toImmutableList())));
CobblemonRecipeCategories.Companion.getCustomAggregateCategories().forEach((recipeBookCategories, list) -> map2.put(recipeBookCategories, (List)list.stream().flatMap((recipeBookCategoriesx) -> ((List)map2.getOrDefault(recipeBookCategoriesx, ImmutableList.of())).stream()).collect(ImmutableList.toImmutableList())));
RecipeBookCategories.AGGREGATE_CATEGORIES.forEach((recipeBookCategories, list) -> map2.put(recipeBookCategories, (List) list.stream().flatMap((recipeBookCategoriesx) -> ((List) map2.getOrDefault(recipeBookCategoriesx, ImmutableList.of())).stream()).collect(ImmutableList.toImmutableList())));
CobblemonRecipeCategories.Companion.getCustomAggregateCategories().forEach((recipeBookCategories, list) -> map2.put(recipeBookCategories, (List) list.stream().flatMap((recipeBookCategoriesx) -> ((List) map2.getOrDefault(recipeBookCategoriesx, ImmutableList.of())).stream()).collect(ImmutableList.toImmutableList())));
this.collectionsByTab = ImmutableMap.copyOf(map2);
this.allCollections = builder.build();
@@ -10,27 +10,51 @@ package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.CobblemonNetwork;
import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.api.orientation.OrientationController;
import com.cobblemon.mod.common.api.riding.Seat;
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate;
import com.cobblemon.mod.common.client.render.MatrixWrapper;
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState;
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel;
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket;
import com.mojang.authlib.GameProfile;
import net.minecraft.client.CameraType;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
import org.joml.Matrix3f;
import org.joml.Vector3f;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Map;
@Mixin(LocalPlayer.class)
public abstract class LocalPlayerMixin extends LivingEntity {
public abstract class LocalPlayerMixin extends AbstractClientPlayer implements OrientationControllable{
@Unique Matrix3f cobblemon$lastOrientation;
protected LocalPlayerMixin(EntityType<? extends LivingEntity> entityType, Level level) {
super(entityType, level);
@Shadow
private float jumpRidingScale;
public LocalPlayerMixin(ClientLevel clientLevel, GameProfile gameProfile) {
super(clientLevel, gameProfile);
}
// @Inject(method = "sendPosition", at = @At("TAIL"))
@@ -76,4 +100,73 @@ public abstract class LocalPlayerMixin extends LivingEntity {
if (!(this instanceof OrientationControllable controllable)) return;
controllable.getOrientationController().setActive(false);
}
@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) {
var rideValue = pokemonEntity.<Float>ifRidingAvailableSupply(null, (behaviour, settings, state) -> {
if (behaviour.canJump(settings, state, pokemonEntity, player)) return null;
return behaviour.setRideBar(settings, state, pokemonEntity, player);
});
if (rideValue != null) {
cir.setReturnValue(rideValue);
}
}
}
@Override
public HitResult pick(double hitDistance, float partialTicks, boolean hitFluids) {
Entity vehicle = this.getVehicle();
if (vehicle instanceof PokemonEntity pokemonEntity) {
int seatIndex = pokemonEntity.getPassengers().indexOf(this);
Seat seat = pokemonEntity.getSeats().get(seatIndex);
PokemonClientDelegate delegate = (PokemonClientDelegate) pokemonEntity.getDelegate();
MatrixWrapper locator = delegate.getLocatorStates().get(seat.getLocator());
if (locator == null) {
super.pick(hitDistance, partialTicks, hitFluids);
}
Vec3 locatorOffset = new Vec3(locator.getMatrix().getTranslation(new Vector3f()));
OrientationController controller = this.getOrientationController();
float currEyeHeight = this.getEyeHeight();
Vector3f offset = new Vector3f(new Vector3f(0f, currEyeHeight - (this.getBbHeight() / 2), 0f));
if (Minecraft.getInstance().options.getCameraType() == CameraType.FIRST_PERSON) {
PosableModel model = VaryingModelRepository.INSTANCE.getPoser(pokemonEntity.getPokemon().getSpecies().getResourceIdentifier(), new FloatingState());
offset.add(cobblemon$getFirstPersonOffset(model, seat));
}
Matrix3f orientation = controller.isActive() && controller.getOrientation() != null ? controller.getOrientation() : new Matrix3f();
Vec3 rotatedEyeHeight = new Vec3(orientation.transform(offset));
Vec3 eyePosition = locatorOffset.add(pokemonEntity.position()).add(rotatedEyeHeight);
Vec3 viewVector = this.getViewVector(partialTicks);
Vec3 viewDistanceVector = eyePosition.add(viewVector.x * hitDistance, viewVector.y * hitDistance, viewVector.z * hitDistance);
return this.level()
.clip(
new ClipContext(
eyePosition, viewDistanceVector, ClipContext.Block.OUTLINE, hitFluids ? net.minecraft.world.level.ClipContext.Fluid.ANY : net.minecraft.world.level.ClipContext.Fluid.NONE, this
)
);
}
return super.pick(hitDistance, partialTicks, hitFluids);
}
@Unique
private static @NotNull Vector3f cobblemon$getFirstPersonOffset(PosableModel model, Seat seat) {
Map<String, Vec3> cameraOffsets = model.getFirstPersonCameraOffset();
if (cameraOffsets.containsKey(seat.getLocator())) {
return cameraOffsets.get(seat.getLocator()).toVector3f();
} else {
return new Vector3f(0f, 0f, 0f);
}
}
}
@@ -50,10 +50,10 @@ public class RecipeBookCategoriesMixin {
private static void cobblemon$addRecipeBookType(CallbackInfo ci) {
ArrayList<RecipeBookCategories> types = new ArrayList<>(List.of($VALUES));
types.add(cobblemon$createCategory("COOKING_POT_SEARCH", $VALUES.length, new ItemStack(Items.COMPASS)));
types.add(cobblemon$createCategory("COOKING_POT_FOODS", $VALUES.length + 1, new ItemStack(CobblemonItems.ROASTED_LEEK)));
types.add(cobblemon$createCategory("COOKING_POT_MEDICINES", $VALUES.length + 2, new ItemStack(CobblemonItems.HP_UP)));
types.add(cobblemon$createCategory("COOKING_POT_BAITS", $VALUES.length + 3, new ItemStack(CobblemonItems.PERSIM_BERRY)));
types.add(cobblemon$createCategory("COOKING_POT_MISC", $VALUES.length + 4, new ItemStack(CobblemonItems.MIRROR_HERB)));
types.add(cobblemon$createCategory("COOKING_POT_FOODS", $VALUES.length + 1, new ItemStack(CobblemonItems.LEEK_AND_POTATO_STEW)));
types.add(cobblemon$createCategory("COOKING_POT_MEDICINES", $VALUES.length + 2, new ItemStack(CobblemonItems.POTION)));
types.add(cobblemon$createCategory("COOKING_POT_COMPLEX_DISHES", $VALUES.length + 3, new ItemStack(CobblemonItems.POKE_PUFF)));
types.add(cobblemon$createCategory("COOKING_POT_MISC", $VALUES.length + 4, new ItemStack(CobblemonItems.PROTEIN)));
$VALUES = types.toArray(RecipeBookCategories[]::new);
}
@@ -64,7 +64,7 @@ public class RecipeBookCategoriesMixin {
CobblemonRecipeCategories.COOKING_POT_SEARCH.toVanillaCategory(),
CobblemonRecipeCategories.COOKING_POT_FOODS.toVanillaCategory(),
CobblemonRecipeCategories.COOKING_POT_MEDICINES.toVanillaCategory(),
CobblemonRecipeCategories.COOKING_POT_BAITS.toVanillaCategory(),
CobblemonRecipeCategories.COOKING_POT_COMPLEX_DISHES.toVanillaCategory(),
CobblemonRecipeCategories.COOKING_POT_MISC.toVanillaCategory());
cir.setReturnValue(var10000);
return;
@@ -0,0 +1,60 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.client;
import net.minecraft.client.searchtree.IdSearchTree;
import net.minecraft.client.searchtree.SearchTree;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@Mixin(IdSearchTree.class)
public abstract class SearchTreeMixin {
@Unique
private static final ThreadLocal<Boolean> reentryFlag = ThreadLocal.withInitial(() -> false);
/**
* Runs an additional search using the original search term where every instance of 'e' is replaced with 'é'
* Appends additional search results to original search results.
*/
@Inject(method = "search(Ljava/lang/String;)Ljava/util/List;", at = @At("RETURN"), cancellable = true)
private void onSearch(String string, CallbackInfoReturnable<List> cir) {
// If flag is true, skip to avoid infinite loop
if (reentryFlag.get()) {
return;
}
try {
reentryFlag.set(true);
List originalResults = cir.getReturnValue();
if (!string.contains("poke")) {
return;
}
String modifiedString = string.replace("poke", "poké");
List additionalResults = ((SearchTree)this).search(modifiedString);
Set combinedSet = new LinkedHashSet<>();
combinedSet.addAll(originalResults);
combinedSet.addAll(additionalResults);
cir.setReturnValue(new ArrayList<>(combinedSet));
} finally {
reentryFlag.set(false);
}
}
}
@@ -40,9 +40,9 @@ import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
import com.cobblemon.mod.common.api.scheduling.ServerRealTimeTaskTracker
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
import com.cobblemon.mod.common.api.spawning.BestSpawner
import com.cobblemon.mod.common.api.spawning.CobblemonSpawningProspector
import com.cobblemon.mod.common.api.spawning.context.AreaContextResolver
import com.cobblemon.mod.common.api.spawning.prospecting.SpawningProspector
import com.cobblemon.mod.common.api.spawning.CobblemonSpawningZoneGenerator
import com.cobblemon.mod.common.api.spawning.position.AreaSpawnablePositionResolver
import com.cobblemon.mod.common.api.spawning.SpawningZoneGenerator
import com.cobblemon.mod.common.api.starter.StarterHandler
import com.cobblemon.mod.common.api.storage.PokemonStoreManager
import com.cobblemon.mod.common.api.storage.adapter.conversions.ReforgedConversion
@@ -63,13 +63,10 @@ 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.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.*
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.block.DispenserBehaviorRegistry
import com.cobblemon.mod.common.client.CobblemonPack
import com.cobblemon.mod.common.command.argument.*
import com.cobblemon.mod.common.config.CobblemonConfig
@@ -91,23 +88,11 @@ 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.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.*
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.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.util.*
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
@@ -115,20 +100,8 @@ 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.core.registries.Registries
import net.minecraft.resources.ResourceKey
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
@@ -139,6 +112,17 @@ 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 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
object Cobblemon {
const val MODID = CobblemonBuildDetails.MOD_ID
@@ -160,8 +144,8 @@ object Cobblemon {
var isDedicatedServer = false
val showdownThread = ShowdownThread()
lateinit var config: CobblemonConfig
var prospector: SpawningProspector = CobblemonSpawningProspector
var areaContextResolver: AreaContextResolver = object : AreaContextResolver {}
var spawningZoneGenerator: SpawningZoneGenerator = CobblemonSpawningZoneGenerator
var areaSpawnablePositionResolver: AreaSpawnablePositionResolver = object : AreaSpawnablePositionResolver {}
val bestSpawner = BestSpawner
val battleRegistry = BattleRegistry
var storage = PokemonStoreManager()
@@ -213,6 +197,7 @@ object Cobblemon {
implementation.registerEntityDataSerializers()
implementation.registerCriteria()
implementation.registerEntitySubPredicates()
DispenserBehaviorRegistry.registerDispenserBehaviors()
DropEntry.register("command", CommandDropEntry::class.java)
DropEntry.register("item", ItemDropEntry::class.java, isDefault = true)
@@ -97,6 +97,18 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
val CAMPFIRE: BlockEntityType<CampfireBlockEntity> = this.create("campfire_pot",
BlockEntityType.Builder.of(::CampfireBlockEntity, CobblemonBlocks.CAMPFIRE).build(null)
)
@JvmField
val COPPER_OVEN: BlockEntityType<CopperOvenBlockEntity> = this.create("copper_oven",
BlockEntityType.Builder.of(::CopperOvenBlockEntity, CobblemonBlocks.COPPER_OVEN).build(null)
)
@JvmField
val COPPER_WASHER: BlockEntityType<CopperWasherBlockEntity> = this.create("copper_washer",
BlockEntityType.Builder.of(::CopperWasherBlockEntity, CobblemonBlocks.COPPER_WASHER).build(null)
)
@JvmField
val COPPER_FRIDGE: BlockEntityType<CopperFridgeBlockEntity> = this.create("copper_fridge",
BlockEntityType.Builder.of(::CopperFridgeBlockEntity, CobblemonBlocks.COPPER_FRIDGE).build(null)
)
/*@JvmField
val LURE_CAKE: BlockEntityType<LureCakeBlockEntity> =
@@ -15,10 +15,14 @@ import com.cobblemon.mod.common.block.LecternBlock
import com.cobblemon.mod.common.block.MintBlock.MintType
import com.cobblemon.mod.common.block.campfirepot.CampfirePotBlock
import com.cobblemon.mod.common.block.chest.GildedChestBlock
import com.cobblemon.mod.common.block.general.BaleBlock
import com.cobblemon.mod.common.block.grower.SaccharineTreeGrower
import com.cobblemon.mod.common.block.sign.CobblemonHangingSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonWallHangingSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonWallSignBlock
import com.cobblemon.mod.common.block.general.HorizontalRotationCarpetBlock
import com.cobblemon.mod.common.block.general.HorizontalRotationalBlock
import com.cobblemon.mod.common.mixin.invoker.*
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.util.cobblemonResource
@@ -175,11 +179,11 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
val SACCHARINE_HONEY_LOG = this.create("saccharine_honey_log", SaccharineHoneyLogBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0F).sound(SoundType.WOOD).ignitedByLava()))
@JvmField
val STRIPPED_SACCHARINE_LOG = this.create("stripped_saccharine_log", SaccharineStrippedLogBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_LIGHT_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0F).sound(SoundType.WOOD).ignitedByLava())) //log("stripped_saccharine_log")
val STRIPPED_SACCHARINE_LOG = this.create("stripped_saccharine_log", RotatedPillarBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_LIGHT_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0F).sound(SoundType.WOOD).ignitedByLava())) //log("stripped_saccharine_log")
@JvmField
val SACCHARINE_WOOD = log("saccharine_wood")
@JvmField
val STRIPPED_SACCHARINE_WOOD = this.create("stripped_saccharine_wood", SaccharineStrippedLogBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_LIGHT_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0F).sound(SoundType.WOOD).ignitedByLava())) //log("stripped_saccharine_log")
val STRIPPED_SACCHARINE_WOOD = this.create("stripped_saccharine_wood", RotatedPillarBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_LIGHT_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0F).sound(SoundType.WOOD).ignitedByLava())) //log("stripped_saccharine_log")
@JvmField
val SACCHARINE_PLANKS = this.create("saccharine_planks", Block(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_LIGHT_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0f, 3.0f).sound(SoundType.WOOD)))
@JvmField
@@ -222,7 +226,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val SACCHARINE_TRAPDOOR = this.create("saccharine_trapdoor", TrapdoorBlockInvoker.`cobblemon$create`(SACCHARINE_BLOCK_SET_TYPE, BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).strength(3.0F).sound(SoundType.WOOD).noOcclusion()))
@JvmField
val SACCHARINE_SAPLING = this.create("saccharine_sapling", SaccharineSaplingBlock(PLANT_PROPERTIES))
val SACCHARINE_SAPLING = this.create("saccharine_sapling", SaplingBlock(SaccharineTreeGrower(), PLANT_PROPERTIES))
@JvmField
val MEDICINAL_LEEK = this.create("medicinal_leek", MedicinalLeekBlock(BlockBehaviour.Properties.of().pushReaction(PushReaction.DESTROY).ignitedByLava().mapColor(MapColor.CRIMSON_NYLIUM).noCollission().randomTicks().instabreak().sound(CobblemonSounds.MEDICINAL_LEEK_SOUNDS)))
@@ -446,7 +450,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val CAMPFIRE = create("campfire", CampfireBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOD).noOcclusion().pushReaction(PushReaction.BLOCK).mapColor(MapColor.PODZOL).strength(2.0F).lightLevel { if ((it.getValue(CampfireBlock.SOUL) as Boolean)) 9 else 14 }))
@JvmField
val RELIC_COIN_POUCH = create("relic_coin_pouch", CoinPouchBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.RELIC_COIN_POUCH_SOUNDS).pushReaction(PushReaction.DESTROY).noOcclusion(), true))
@JvmField
@@ -488,6 +492,17 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val DISPLAY_CASE = create("display_case", DisplayCaseBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.DISPLAY_CASE_SOUNDS).noOcclusion().pushReaction(PushReaction.BLOCK).mapColor(MapColor.STONE).strength(0.3F)))
@JvmField
val COPPER_FAN = create("copper_fan", CopperFanBlock(BlockBehaviour.Properties.of().pushReaction(PushReaction.DESTROY).mapColor(MapColor.COLOR_ORANGE).requiresCorrectToolForDrops().strength(3.0F, 6.0F).sound(SoundType.COPPER)))
@JvmField
val COPPER_MOWER = create("copper_mower", CopperMowerBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_ORANGE).requiresCorrectToolForDrops().strength(3.0F, 6.0F).sound(SoundType.COPPER)))
@JvmField
val COPPER_OVEN = create("copper_oven", CopperOvenBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_ORANGE).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(3.0F, 6.0F).sound(SoundType.COPPER)))
@JvmField
val COPPER_WASHER = this.create("copper_washer", CopperWasherBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_ORANGE).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(3.0F, 6.0F).sound(SoundType.COPPER)))
@JvmField
val COPPER_FRIDGE = this.create("copper_fridge", CopperFridgeBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_ORANGE).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(3.0F, 6.0F).sound(SoundType.COPPER)))
@JvmField
val INCENSE_SWEET = create("incense_sweet", SweetIncenseBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.DISPLAY_CASE_SOUNDS).noOcclusion().pushReaction(PushReaction.BLOCK).mapColor(MapColor.STONE).strength(0.3f)))
@@ -515,6 +530,30 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val HEARTY_GRAINS = this.create("hearty_grains", HeartyGrainsBlock(BlockBehaviour.Properties.of().pushReaction(PushReaction.DESTROY).ignitedByLava().mapColor(MapColor.PLANT).noCollission().randomTicks().instabreak().sound(CobblemonSounds.VIVICHOKE_SOUNDS)))
@JvmField
val POTTED_RED_APRICORN_SAPLING = this.create("potted_red_apricorn_sapling", BlocksInvoker.createFlowerPotBlock(RED_APRICORN_SAPLING))
@JvmField
val POTTED_YELLOW_APRICORN_SAPLING = this.create("potted_yellow_apricorn_sapling", BlocksInvoker.createFlowerPotBlock(YELLOW_APRICORN_SAPLING))
@JvmField
val POTTED_GREEN_APRICORN_SAPLING = this.create("potted_green_apricorn_sapling", BlocksInvoker.createFlowerPotBlock(GREEN_APRICORN_SAPLING))
@JvmField
val POTTED_BLUE_APRICORN_SAPLING = this.create("potted_blue_apricorn_sapling", BlocksInvoker.createFlowerPotBlock(BLUE_APRICORN_SAPLING))
@JvmField
val POTTED_PINK_APRICORN_SAPLING = this.create("potted_pink_apricorn_sapling", BlocksInvoker.createFlowerPotBlock(PINK_APRICORN_SAPLING))
@JvmField
val POTTED_BLACK_APRICORN_SAPLING = this.create("potted_black_apricorn_sapling", BlocksInvoker.createFlowerPotBlock(BLACK_APRICORN_SAPLING))
@JvmField
val POTTED_WHITE_APRICORN_SAPLING = this.create("potted_white_apricorn_sapling", BlocksInvoker.createFlowerPotBlock(WHITE_APRICORN_SAPLING))
@JvmField
val POTTED_SACCHARINE_SAPLING = this.create("potted_saccharine_sapling", BlocksInvoker.createFlowerPotBlock(SACCHARINE_SAPLING))
@JvmField
val HEARTY_GRAIN_BALE = this.create("hearty_grain_bale", BaleBlock(BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).instrument(NoteBlockInstrument.BANJO).strength(0.5F).sound(SoundType.GRASS)))
@JvmField
val TATAMI_BLOCK = this.create("tatami_block", HorizontalRotationalBlock(BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.PLANT).sound(SoundType.GRASS)))
@JvmField
val TATAMI_MAT = this.create("tatami_mat", HorizontalRotationCarpetBlock(BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.PLANT).sound(SoundType.GRASS)))
/**
* Returns a map of all the blocks that can be stripped with an axe in the format of input - output.
*
@@ -68,6 +68,8 @@ object CobblemonCommands {
MarkGiveCommand.register(dispatcher)
MarkTakeCommand.register(dispatcher)
MarkGiveAllCommand.register(dispatcher)
PcSearchCommand.register(dispatcher)
PcTakeCommand.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
@@ -8,18 +8,14 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.block.PotComponent
import com.cobblemon.mod.common.item.components.BaitEffectsComponent
import com.cobblemon.mod.common.item.components.FlavourComponent
import com.cobblemon.mod.common.item.components.FoodColourComponent
import com.cobblemon.mod.common.item.components.HeldItemCapableComponent
import com.cobblemon.mod.common.item.components.PokemonItemComponent
import com.cobblemon.mod.common.item.components.RodBaitComponent
import com.cobblemon.mod.common.item.components.*
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.mojang.serialization.Codec
import net.minecraft.core.Registry
import net.minecraft.core.component.DataComponentType
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
import net.minecraft.network.codec.ByteBufCodecs
import net.minecraft.resources.ResourceKey
import net.minecraft.resources.ResourceLocation
@@ -60,6 +56,25 @@ object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>
.networkSynchronized(FoodColourComponent.PACKET_CODEC)
.build())
val INGREDIENT: DataComponentType<IngredientComponent> = create("ingredient", DataComponentType.builder<IngredientComponent>()
.persistent(IngredientComponent.CODEC)
.networkSynchronized(IngredientComponent.PACKET_CODEC)
.build())
val FOOD: DataComponentType<FoodComponent> = create("food", DataComponentType.builder<FoodComponent>()
.persistent(FoodComponent.CODEC)
.networkSynchronized(FoodComponent.PACKET_CODEC)
.build())
val MOB_EFFECTS: DataComponentType<MobEffectsComponent> = create("mob_effects", DataComponentType.builder<MobEffectsComponent>()
.persistent(MobEffectsComponent.CODEC)
.networkSynchronized(MobEffectsComponent.PACKET_CODEC)
.build())
val CRAFTED: DataComponentType<Boolean> = create("crafted", DataComponentType.builder<Boolean>()
.persistent(Codec.BOOL)
.networkSynchronized(ByteBufCodecs.BOOL)
.build())
fun register() {
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:pokemon_item"), POKEMON_ITEM)
@@ -68,6 +83,9 @@ object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:bait_effects"), BAIT_EFFECTS)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:flavour"), FLAVOUR)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:food_colour"), FOOD_COLOUR)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:ingredient"), INGREDIENT)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:food"), FOOD)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:mob_effects"), MOB_EFFECTS)
}
override val registry = BuiltInRegistries.DATA_COMPONENT_TYPE
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.api.item.ability.AbilityChanger
import com.cobblemon.mod.common.api.mulch.MulchVariant
import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.api.pokemon.Natures
import com.cobblemon.mod.common.api.pokemon.stats.Stat
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.pokemon.status.Statuses
import com.cobblemon.mod.common.api.text.blue
@@ -34,10 +35,13 @@ import com.cobblemon.mod.common.item.berry.PPRestoringBerryItem
import com.cobblemon.mod.common.item.berry.PortionHealingBerryItem
import com.cobblemon.mod.common.item.berry.StatusCuringBerryItem
import com.cobblemon.mod.common.item.berry.VolatileCuringBerryItem
import com.cobblemon.mod.common.item.food.PonigiriItem
import com.cobblemon.mod.common.item.food.SinisterTeaItem
import com.cobblemon.mod.common.item.interactive.*
import com.cobblemon.mod.common.item.interactive.ability.AbilityChangeItem
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.pokeball.PokeBall
import com.cobblemon.mod.common.pokemon.IVs
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.core.Registry
@@ -53,6 +57,8 @@ import net.minecraft.world.food.FoodProperties
import net.minecraft.world.item.BlockItem
import net.minecraft.world.item.HangingSignItem
import net.minecraft.world.item.Item
import net.minecraft.world.item.Item.Properties
import net.minecraft.world.item.ItemNameBlockItem
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraft.world.item.Rarity
@@ -186,22 +192,29 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
val campfire_pots = mutableListOf<CampfirePotItem>()
@JvmField
val CAMPFIRE_POT_BLACK = campfirePotItem(CobblemonBlocks.BLACK_CAMPFIRE_POT, "black")
val CAMPFIRE_POT_RED = campfirePotItem(CobblemonBlocks.RED_CAMPFIRE_POT, "red")
@JvmField
val CAMPFIRE_POT_BLUE = campfirePotItem(CobblemonBlocks.BLUE_CAMPFIRE_POT, "blue")
val CAMPFIRE_POT_YELLOW = campfirePotItem(CobblemonBlocks.YELLOW_CAMPFIRE_POT, "yellow")
@JvmField
val CAMPFIRE_POT_GREEN = campfirePotItem(CobblemonBlocks.GREEN_CAMPFIRE_POT, "green")
@JvmField
val CAMPFIRE_POT_BLUE = campfirePotItem(CobblemonBlocks.BLUE_CAMPFIRE_POT, "blue")
@JvmField
val CAMPFIRE_POT_PINK = campfirePotItem(CobblemonBlocks.PINK_CAMPFIRE_POT, "pink")
@JvmField
val CAMPFIRE_POT_RED = campfirePotItem(CobblemonBlocks.RED_CAMPFIRE_POT, "red")
val CAMPFIRE_POT_BLACK = campfirePotItem(CobblemonBlocks.BLACK_CAMPFIRE_POT, "black")
@JvmField
val CAMPFIRE_POT_WHITE = campfirePotItem(CobblemonBlocks.WHITE_CAMPFIRE_POT, "white")
@JvmField
val CAMPFIRE_POT_YELLOW = campfirePotItem(CobblemonBlocks.YELLOW_CAMPFIRE_POT, "yellow")
@JvmField
val Hearty_Grains = compostableItem("hearty_grains", HeartyGrainsItem(CobblemonBlocks.HEARTY_GRAINS))
val HEARTY_GRAINS = compostableItem("hearty_grains", ItemNameBlockItem(CobblemonBlocks.HEARTY_GRAINS, Properties().rarity(Rarity.COMMON)))
@JvmField
val HEARTY_GRAIN_BALE = compostableBlockItem("hearty_grain_bale", CobblemonBlocks.HEARTY_GRAIN_BALE, 0.85f)
@JvmField
val TATAMI_BLOCK = blockItem("tatami_block", CobblemonBlocks.TATAMI_BLOCK)
@JvmField
val TATAMI_MAT = blockItem("tatami_mat", CobblemonBlocks.TATAMI_MAT)
@JvmField
val VIVICHOKE = compostableItem("vivichoke")
@@ -334,10 +347,10 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val SACCHARINE_HANGING_SIGN = this.create("saccharine_hanging_sign", HangingSignItem(CobblemonBlocks.SACCHARINE_HANGING_SIGN, CobblemonBlocks.SACCHARINE_WALL_HANGING_SIGN, Item.Properties().stacksTo(16)))
@JvmField
val SACCHARINE_SAPLING = saccharineSaplingItem("saccharine_sapling", SaccharineSaplingItem(CobblemonBlocks.SACCHARINE_SAPLING))
val SACCHARINE_SAPLING = compostableBlockItem("saccharine_sapling", CobblemonBlocks.SACCHARINE_SAPLING)
@JvmField
val BUGWORT = bugwortItem("bugwort", BugwortItem(CobblemonBlocks.BUGWORT))
val BUGWORT = compostableBlockItem("bugwort", CobblemonBlocks.BUGWORT)
@JvmField
val POKE_BAIT = noSettingsItem("poke_bait")
@@ -348,260 +361,105 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
val aprijuices = mutableListOf<AprijuiceItem>()
@JvmField
val APRIJUICE_BLACK = aprijuiceItem(Apricorn.BLACK)
@JvmField
val APRIJUICE_RED = aprijuiceItem(Apricorn.RED)
@JvmField
val APRIJUICE_BLUE = aprijuiceItem(Apricorn.BLUE)
@JvmField
val APRIJUICE_GREEN = aprijuiceItem(Apricorn.GREEN)
@JvmField
val APRIJUICE_YELLOW = aprijuiceItem(Apricorn.YELLOW)
@JvmField
val APRIJUICE_WHITE = aprijuiceItem(Apricorn.WHITE)
val APRIJUICE_GREEN = aprijuiceItem(Apricorn.GREEN)
@JvmField
val APRIJUICE_BLUE = aprijuiceItem(Apricorn.BLUE)
@JvmField
val APRIJUICE_PINK = aprijuiceItem(Apricorn.PINK)
@JvmField
val APRIJUICE_BLACK = aprijuiceItem(Apricorn.BLACK)
@JvmField
val APRIJUICE_WHITE = aprijuiceItem(Apricorn.WHITE)
@JvmField
val POKE_PUFF = noSettingsItem("poke_puff") // todo make a PokePuffItem class for friendship boosting purposes
val PONIGIRI = create("ponigiri", PonigiriItem())
@JvmField
val SINISTER_TEA = create("sinister_tea", SinisterTeaItem())
@JvmField
val POKE_PUFF = pokepuffItem("poke_puff")
// FOODS
@JvmField
val SWEET_HEART = noSettingsItem("sweet_heart") // todo make a SweetHeartItem class for breeding purposes
@JvmField
val PEWTER_CRUNCHIES = create("pewter_crunchies", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
val TASTY_TAIL = noSettingsItem("tasty_tail")
@JvmField
val RAGE_CANDY_BAR = create("rage_candy_bar", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
@JvmField // todo get final values for this from vera
val PEWTER_CRUNCHIES = regionalFoodItem("pewter_crunchies", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f, false)
@JvmField
val LAVA_COOKIE = create("lava_cookie", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
@JvmField // todo get final values for this from vera
val RAGE_CANDY_BAR = regionalFoodItem("rage_candy_bar", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f, false)
@JvmField
val OLD_GATEAU = create("old_gateau", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
@JvmField // todo get final values for this from vera
val LAVA_COOKIE = regionalFoodItem("lava_cookie", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f)
@JvmField
val CASTELIACONE = create("casteliacone", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
@JvmField // todo get final values for this from vera
val OLD_GATEAU = regionalFoodItem("old_gateau", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f)
@JvmField
val SHALOR_SABLE = create("shalor_sable", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
@JvmField // todo get final values for this from vera
val CASTELIACONE = regionalFoodItem("casteliacone", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f)
@JvmField
val LUMIOSE_GALETTE = create("lumiose_galette", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
@JvmField // todo get final values for this from vera
val SHALOUR_SABLE = regionalFoodItem("shalour_sable", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f)
@JvmField
val BIG_MALASADA = create("big_malasada", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
@JvmField // todo get final values for this from vera
val LUMIOSE_GALETTE = regionalFoodItem("lumiose_galette", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f)
/*@JvmField // todo see what we are doing for these (are there different kinds?)
val CURRY = create("curry", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.usingConvertsTo(Items.BOWL)
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})*/
@JvmField // todo get final values for this from vera
val BIG_MALASADA = regionalFoodItem("big_malasada", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f)
@JvmField
val JUBILIFE_MUFFIN = create("jubilife_muffin", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
@JvmField // todo get final values for this from vera
val SMOKED_TAIL_CURRY = regionalFoodItem("smoked_tail_curry", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f, false, ItemStack(Items.BOWL, 1))
/*@JvmField // todo see what we are doing for these (are there different kinds?)
val SANDWICH = create("sandwich", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.usingConvertsTo(Items.BOWL)
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})*/
@JvmField // todo get final values for this from vera
val JUBILIFE_MUFFIN = regionalFoodItem("jubilife_muffin", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f)
// todo we might need to wait on these for later?
@JvmField // todo get final values for this from vera
val OPEN_FACED_SANDWICH = regionalFoodItem("open_faced_sandwich", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f)
// todo we might need to wait on these for later? These impact battles and may be harder to do
/*@JvmField
val CHOICE_DUMPLING = noSettingsItem("choice_dumpling") // todo make a ChoiceDumpingItem class for breeding purposes
val CHOICE_DUMPLING = noSettingsItem("choice_dumpling") // todo make a ChoiceDumpingItem class for battle purposes
@JvmField
val SWAP_SNACK = noSettingsItem("swap_snack") // todo make a SwapSnackItem class for breeding purposes
val SWAP_SNACK = noSettingsItem("swap_snack") // todo make a SwapSnackItem class for battle purposes
@JvmField
val TWICE_SPICED_BEETROOT = noSettingsItem("twice_spiced_beetroot") // todo make a TwiceSpiceBeetrootItem class for breeding purposes
val TWICE_SPICED_BEETROOT = noSettingsItem("twice_spiced_beetroot") // todo make a TwiceSpiceBeetrootItem class for battle purposes
*/
@JvmField
val POTATO_MOCHI = create("potato_mochi", object : Item(Properties().stacksTo(16)
val POTATO_MOCHI = create("potato_mochi", CobblemonItem(Properties().stacksTo(16)
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.nutrition(10) // todo get final values for this from vera
.saturationModifier(1.2F) // todo get final values for this from vera
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
.build())))
@JvmField
val FRIED_RICE = create("fried_rice", object : Item(Properties().stacksTo(16)
val FRIED_RICE = create("fried_rice", CobblemonItem(Properties().stacksTo(16)
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.nutrition(10) // todo get final values for this from vera
.saturationModifier(1.2F) // todo get final values for this from vera
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
.build())))
@JvmField
val CANDIED_APPLE = create("candied_apple", object : Item(Properties().stacksTo(16)
val CANDIED_APPLE = create("candied_apple", CobblemonItem(Properties().stacksTo(16)
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.nutrition(10) // todo get final values for this from vera
.saturationModifier(1.2F) // todo get final values for this from vera
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
.build())))
@JvmField
val CANDIED_BERRY = create("candied_berry", object : Item(Properties().stacksTo(16)
val CANDIED_BERRY = create("candied_berry", CobblemonItem(Properties().stacksTo(16)
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.nutrition(10) // todo get final values for this from vera
.saturationModifier(1.2F) // todo get final values for this from vera
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
@JvmField
val JELLY_DOUGHNUT = create("jelly_doughnut", object : Item(Properties().stacksTo(16)
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
// todo etc?
.build())))
//@JvmField
//val SCATTER_BANG = this.create("scatter_bang", ScatterBangItem(Item.Settings()))
@@ -625,6 +483,17 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val INCENSE_SWEET = blockItem("incense_sweet", CobblemonBlocks.INCENSE_SWEET)
@JvmField
val COPPER_FAN = blockItem("copper_fan", CobblemonBlocks.COPPER_FAN)
@JvmField
val COPPER_MOWER = blockItem("copper_mower", CobblemonBlocks.COPPER_MOWER)
@JvmField
val COPPER_OVEN = blockItem("copper_oven", CobblemonBlocks.COPPER_OVEN)
@JvmField
val COPPER_WASHER = blockItem("copper_washer", CobblemonBlocks.COPPER_WASHER)
@JvmField
val COPPER_FRIDGE = blockItem("copper_fridge", CobblemonBlocks.COPPER_FRIDGE)
// Evolution items
@JvmField val LINK_CABLE = create("link_cable", LinkCableItem())
@@ -665,6 +534,9 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField val AUSPICIOUS_ARMOR = heldItem("auspicious_armor")
@JvmField val MALICIOUS_ARMOR = heldItem("malicious_armor")
@JvmField val SHELL_HELMET = heldItem("shell_helmet")
@JvmField val METAL_ALLOY = noSettingsItem("metal_alloy")
@JvmField val SCROLL_OF_DARKNESS = noSettingsItem("scroll_of_darkness")
@JvmField val SCROLL_OF_WATERS = noSettingsItem("scroll_of_waters")
private val berries = mutableMapOf<ResourceLocation, BerryItem>()
// Plants
@@ -743,6 +615,33 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val GALARICA_NUTS = create("galarica_nuts", GalaricaNutItem())
// Hyper Training Items
val hyperTrainingItems = mutableListOf<HyperTrainingItem>()
@JvmField
val HEALTH_CANDY = hyperTrainingItem("health_candy", 1, setOf(Stats.HP), 0..IVs.MAX_VALUE)
@JvmField
val MIGHTY_CANDY = hyperTrainingItem("mighty_candy", 1, setOf(Stats.ATTACK), 0..IVs.MAX_VALUE)
@JvmField
val TOUGH_CANDY = hyperTrainingItem("tough_candy", 1, setOf(Stats.DEFENCE), 0..IVs.MAX_VALUE)
@JvmField
val SMART_CANDY = hyperTrainingItem("smart_candy", 1, setOf(Stats.SPECIAL_ATTACK), 0..IVs.MAX_VALUE)
@JvmField
val COURAGE_CANDY = hyperTrainingItem("courage_candy", 1, setOf(Stats.SPECIAL_DEFENCE), 0..IVs.MAX_VALUE)
@JvmField
val QUICK_CANDY = hyperTrainingItem("quick_candy", 1, setOf(Stats.SPEED), 0..IVs.MAX_VALUE)
@JvmField
val SICKLY_CANDY = hyperTrainingItem("sickly_candy", -1, setOf(Stats.HP), 0..IVs.MAX_VALUE)
@JvmField
val WEAK_CANDY = hyperTrainingItem("weak_candy", -1, setOf(Stats.ATTACK), 0..IVs.MAX_VALUE)
@JvmField
val BRITTLE_CANDY = hyperTrainingItem("brittle_candy", -1, setOf(Stats.DEFENCE), 0..IVs.MAX_VALUE)
@JvmField
val NUMB_CANDY = hyperTrainingItem("numb_candy", -1, setOf(Stats.SPECIAL_ATTACK), 0..IVs.MAX_VALUE)
@JvmField
val COWARD_CANDY = hyperTrainingItem("coward_candy", -1, setOf(Stats.SPECIAL_DEFENCE), 0..IVs.MAX_VALUE)
@JvmField
val SLOW_CANDY = hyperTrainingItem("slow_candy", -1, setOf(Stats.SPEED), 0..IVs.MAX_VALUE)
// Medicine
@JvmField
val RARE_CANDY = candyItem("rare_candy", Rarity.RARE) { _, pokemon -> pokemon.getExperienceToNextLevel() }
@@ -797,11 +696,11 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val MEDICINAL_LEEK = heldItem("medicinal_leek", MedicinalLeekItem(CobblemonBlocks.MEDICINAL_LEEK, Item.Properties().food(FoodProperties.Builder().fast().nutrition(1).saturationModifier(0.2f).build())), "leek")
@JvmField
val ROASTED_LEEK = create("roasted_leek", Item(Item.Properties().food(FoodProperties.Builder().fast().nutrition(3).saturationModifier(0.3f).build())))
val ROASTED_LEEK = create("roasted_leek", CobblemonItem(Item.Properties().food(FoodProperties.Builder().fast().nutrition(3).saturationModifier(0.3f).build())))
@JvmField
val BRAISED_VIVICHOKE = create("braised_vivichoke", Item(Item.Properties().food(FoodProperties.Builder().nutrition(6).saturationModifier(0.6f).build())))
val BRAISED_VIVICHOKE = create("braised_vivichoke", foodItem(6, 0.6F))
@JvmField
val VIVICHOKE_DIP = create("vivichoke_dip", object : Item(Properties().stacksTo(1)
val VIVICHOKE_DIP = create("vivichoke_dip", object : CobblemonItem(Properties().stacksTo(1)
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
@@ -821,13 +720,15 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val PEP_UP_FLOWER = compostableBlockItem("pep_up_flower", CobblemonBlocks.PEP_UP_FLOWER)
@JvmField
val MEDICINAL_BREW = create("medicinal_brew", Item(Item.Properties()))
val MEDICINAL_BREW = noSettingsItem("medicinal_brew")
@JvmField
val REMEDY = create("remedy", RemedyItem(RemedyItem.NORMAL))
@JvmField
val FINE_REMEDY = create("fine_remedy", RemedyItem(RemedyItem.FINE))
@JvmField
val SUPERB_REMEDY = create("superb_remedy", RemedyItem(RemedyItem.SUPERB))
@JvmField
val MOOMOO_MILK = noSettingsItem("moomoo_milk")
@JvmField
val POTION = create("potion", PotionItem(PotionType.POTION))
@@ -843,7 +744,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val HEAL_POWDER = create("heal_powder", HealPowderItem())
@JvmField
val LEEK_AND_POTATO_STEW = create("leek_and_potato_stew", Item(Item.Properties().food(FoodProperties.Builder().nutrition(8).saturationModifier(0.6f).usingConvertsTo(Items.BOWL).build()).stacksTo(1)))
val LEEK_AND_POTATO_STEW = create("leek_and_potato_stew", CobblemonItem(Item.Properties().food(FoodProperties.Builder().nutrition(8).saturationModifier(0.6f).usingConvertsTo(Items.BOWL).build()).stacksTo(1)))
@JvmField
val REVIVE = create("revive", ReviveItem(max = false))
@JvmField
@@ -1062,8 +963,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
val CHOICE_SCARF = heldItem("choice_scarf")
@JvmField
val CLEANSE_TAG = heldItem("cleanse_tag")
// @JvmField
// val CLEAR_AMULET = heldItem("clear_amulet")
@JvmField
val CLEAR_AMULET = heldItem("clear_amulet")
@JvmField
val COVERT_CLOAK = heldItem("covert_cloak")
@JvmField
@@ -1092,16 +993,16 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
val FOCUS_SASH = heldItem("focus_sash")
@JvmField
val GRASSY_SEED = heldItem("grassy_seed")
// @JvmField
// val GRIP_CLAW = heldItem("grip_claw")
@JvmField
val GRIP_CLAW = heldItem("grip_claw")
@JvmField
val HARD_STONE = heldItem("hard_stone")
@JvmField
val HEAVY_DUTY_BOOTS = heldItem("heavy_duty_boots")
@JvmField
val IRON_BALL = heldItem("iron_ball")
// @JvmField
// val LAGGING_TAIL = heldItem("lagging_tail")
@JvmField
val LAGGING_TAIL = heldItem("lagging_tail")
@JvmField
val LEFTOVERS = heldItem("leftovers")
@JvmField
@@ -1114,8 +1015,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
val LOADED_DICE = heldItem("loaded_dice")
@JvmField
val LUCKY_EGG = heldItem("lucky_egg")
// @JvmField
// val LUMINOUS_MOSS = heldItem("luminous_moss")
@JvmField
val LUMINOUS_MOSS = heldItem("luminous_moss")
@JvmField
val MAGNET = heldItem("magnet")
@JvmField
@@ -1642,6 +1543,44 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
return item
}
private fun pokepuffItem(name: String): PokePuffItem {
val item = create("poke_puff", PokePuffItem())
return item
}
private fun regionalFoodItem(
name: String,
stacksTo: Int,
nutrition: Int,
saturationModifier: Float,
effect: MobEffectInstance? = null,
effectChance: Float? = null,
alwaysEdible: Boolean = false,
convertsToOnUse: ItemStack? = null
): RegionalFoodItem {
val foodPropertiesBuilder = FoodProperties.Builder()
.nutrition(nutrition)
.saturationModifier(saturationModifier)
if (effect != null && effectChance != null) {
foodPropertiesBuilder.effect(effect, effectChance)
}
if (alwaysEdible == true) {
foodPropertiesBuilder.alwaysEdible()
}
if (convertsToOnUse != null && !convertsToOnUse.isEmpty) {
foodPropertiesBuilder.usingConvertsTo(convertsToOnUse.item)
}
val properties = Item.Properties()
.stacksTo(stacksTo)
.food(foodPropertiesBuilder.build())
return create(name, RegionalFoodItem(properties))
}
private fun heldItem(name: String, remappedName: String? = null): CobblemonItem = create(
name,
CobblemonItem(Item.Properties()).also {
@@ -1653,11 +1592,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
private fun heldItem(name: String, item: Item, remappedName: String? = null) = create(
name = name,
entry = item.also {
if (remappedName != null) {
remappedName?.let { remappedName ->
CobblemonHeldItemManager.registerRemap(it, remappedName)
CobblemonHeldItemManager.registerRemap(Items.BONE, "thickclub")
CobblemonHeldItemManager.registerRemap(Items.SNOWBALL, "snowball")
CobblemonHeldItemManager.registerRemap(Items.GOLD_BLOCK, "bignugget")
}
}
)
@@ -1687,6 +1623,12 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
return item
}
private fun hyperTrainingItem(name: String, increaseAmount: Int, targetStats: Set<Stat>, validRange: IntRange): HyperTrainingItem {
val item = this.create(name, HyperTrainingItem(increaseAmount, targetStats, validRange))
hyperTrainingItems.add(item)
return item
}
private fun apricornItem(name: String, apricornItem: ApricornItem): ApricornItem {
val finalName = "${name}_apricorn"
val item = this.create(finalName, apricornItem)
@@ -1701,20 +1643,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
return item
}
private fun saccharineSaplingItem(name: String, saccharineSaplingItem: SaccharineSaplingItem): SaccharineSaplingItem {
val finalName = "saccharine_sapling"
val item = this.create(finalName, saccharineSaplingItem)
compostable(item, .65f)
return item
}
private fun bugwortItem(name: String, bugwortItem: BugwortItem): BugwortItem {
val finalName = "bugwort"
val item = this.create(finalName, bugwortItem)
compostable(item, .65f)
return item
}
private fun mintSeed(name: String, mintBlock: MintBlock): Item {
val finalName = "${name}_mint_seeds"
@@ -1731,7 +1659,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
}
private fun compostableItem(name: String, item: Item? = null, increaseLevelChance: Float = .65f): Item {
val createdItem = this.create(name, item ?: Item(Item.Properties()))
val createdItem = this.create(name, item ?: CobblemonItem(Item.Properties()))
compostable(createdItem, increaseLevelChance)
return createdItem
}
@@ -1749,6 +1677,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
}
private fun foodItem(nutrition: Int, saturationModifier: Float): Item {
return Item(Item.Properties().food(FoodProperties.Builder().nutrition(nutrition).saturationModifier(saturationModifier).build()))
return CobblemonItem(Item.Properties().food(FoodProperties.Builder().nutrition(nutrition).saturationModifier(saturationModifier).build()))
}
}
@@ -10,9 +10,7 @@ package com.cobblemon.mod.common
import com.cobblemon.mod.common.block.campfirepot.CookingPotMenu
import com.cobblemon.mod.common.client.gui.cookingpot.CookingPotScreen
import com.cobblemon.mod.common.platform.PlatformRegistry
import net.minecraft.client.gui.screens.MenuScreens
import net.minecraft.core.Registry
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
@@ -259,6 +259,7 @@ object CobblemonNetwork {
// Pokemon Update Packets
list.add(PacketRegisterInfo(FriendshipUpdatePacket.ID, FriendshipUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(FullnessUpdatePacket.ID, FullnessUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(MoveSetUpdatePacket.ID, MoveSetUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(NatureUpdatePacket.ID, NatureUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(ShinyUpdatePacket.ID, ShinyUpdatePacket::decode, PokemonUpdatePacketHandler()))
@@ -36,7 +36,7 @@ object CobblemonPoiTypes: PlatformRegistry<Registry<PoiType>, ResourceKey<Regist
@JvmField
val SACCHARINE_HONEY_LOG = create(SACCHARINE_HONEY_LOG_KEY.location().path, PoiType(getBlockStates(CobblemonBlocks.SACCHARINE_HONEY_LOG), 0, 1))
@JvmField
val INCENSE_SWEET_KEY: ResourceKey<PoiType> = createKey("saccharine_honey_log")
val INCENSE_SWEET_KEY: ResourceKey<PoiType> = createKey("incense_sweet")
@JvmField
val INCENSE_SWEET = create(INCENSE_SWEET_KEY.location().path, PoiType(getBlockStates(CobblemonBlocks.INCENSE_SWEET), 0, 1))
@@ -15,13 +15,13 @@ enum class CobblemonRecipeCategories {
COOKING_POT_SEARCH("COOKING_POT_SEARCH"),
COOKING_POT_FOODS("COOKING_POT_FOODS"),
COOKING_POT_MEDICINES("COOKING_POT_MEDICINES"),
COOKING_POT_BAITS("COOKING_POT_BAITS"),
COOKING_POT_COMPLEX_DISHES("COOKING_POT_COMPLEX_DISHES"),
COOKING_POT_MISC("COOKING_POT_MISC");
companion object {
val customAggregateCategories: Map<RecipeBookCategories, List<RecipeBookCategories>> = mapOf(
COOKING_POT_SEARCH.toVanillaCategory() to listOf(
COOKING_POT_FOODS.toVanillaCategory(), COOKING_POT_MISC.toVanillaCategory(), COOKING_POT_MEDICINES.toVanillaCategory(), COOKING_POT_BAITS.toVanillaCategory()
COOKING_POT_FOODS.toVanillaCategory(), COOKING_POT_MISC.toVanillaCategory(), COOKING_POT_MEDICINES.toVanillaCategory(), COOKING_POT_COMPLEX_DISHES.toVanillaCategory()
)
)
}
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common
import com.cobblemon.mod.common.item.crafting.CookingPotRecipe
import com.cobblemon.mod.common.item.crafting.CookingPotShapelessRecipe
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe
import com.cobblemon.mod.common.platform.PlatformRegistry
import net.minecraft.core.Registry
import net.minecraft.core.registries.BuiltInRegistries
@@ -24,6 +25,8 @@ object CobblemonRecipeSerializers : PlatformRegistry<Registry<RecipeSerializer<*
val COOKING_POT_COOKING: RecipeSerializer<*> = register("cobblemon:cooking_pot", CookingPotRecipe.Serializer())
val COOKING_POT_SHAPELESS: RecipeSerializer<*> = register("cobblemon:cooking_pot_shapeless", CookingPotShapelessRecipe.Serializer())
val BREWING_STAND: RecipeSerializer<*> = register("cobblemon:brewing_stand", BrewingStandRecipe.Serializer())
override val registry: Registry<RecipeSerializer<*>>
get() = BuiltInRegistries.RECIPE_SERIALIZER
override val resourceKey: ResourceKey<Registry<RecipeSerializer<*>>>
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common
import com.cobblemon.mod.common.item.crafting.CookingPotRecipe
import com.cobblemon.mod.common.item.crafting.CookingPotShapelessRecipe
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe
import com.cobblemon.mod.common.platform.PlatformRegistry
import net.minecraft.core.Registry
import net.minecraft.core.registries.BuiltInRegistries
@@ -24,6 +25,8 @@ object CobblemonRecipeTypes : PlatformRegistry<Registry<RecipeType<*>>, Resource
val COOKING_POT_COOKING: RecipeType<CookingPotRecipe> = register("cobblemon:cooking_pot")
val COOKING_POT_SHAPELESS: RecipeType<CookingPotShapelessRecipe> = register("cobblemon:cooking_pot_shapeless")
val BREWING_STAND: RecipeType<BrewingStandRecipe> = register("cobblemon:brewing_stand")
override val registry: Registry<RecipeType<*>>
get() = BuiltInRegistries.RECIPE_TYPE
override val resourceKey: ResourceKey<Registry<RecipeType<*>>>
@@ -125,6 +125,7 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
@JvmField
val MOCHI_USE = this.create("item.medicine.feather.use")
@JvmField
val MULCH_PLACE = this.create("block.mulch.place")
@JvmField
@@ -216,6 +217,8 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
val BERRY_HARVEST = this.create("block.berry_bush.harvest")
@JvmField
val BERRY_EAT = this.create("item.berry.eat")
@JvmField
val BERRY_EAT_FULL = this.create("item.berry.eat.full")
@JvmField
val BIG_ROOT_BREAK = this.create("block.big_root.break")
@@ -32,6 +32,7 @@ class PokemonCriterion(
}
override fun matches(player: ServerPlayer, context: Pokemon): Boolean {
return (species.equals(context.species.resourceIdentifier.path) || species.equals(context.species.resourceIdentifier)) && properties.matches(context)
var speciesCheck = (species.equals(context.species.resourceIdentifier.path) || species.equals(context.species.resourceIdentifier.toString())) || species.equals("any")
return speciesCheck && properties.matches(context)
}
}
@@ -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.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.npc.ai.MeleeAttackTask
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.BattleFlightTask
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
class BattleFlightTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
if (entity !is PokemonEntity) {
return null
}
return BattleFlightTask.create()
}
}
@@ -1,7 +1,7 @@
# Task Configuration
A task configuration is responsible for producing one or multiple tasks as part of a
[BrainConfiguration](../README.md). Tasks are the smallest unit of behaviour in a brain and are executed
[Behaviour Configuration](../README.md). Tasks are the smallest unit of behaviour in a brain and are executed
as part of an activity.
A task configuration can be a simple string that represents the type of task to create, or a JSON object
@@ -94,7 +94,8 @@ interface TaskConfig {
cobblemonResource("point_to_spawn") to PointToSpawnTaskConfig::class.java,
cobblemonResource("eat_grass") to EatGrassTaskConfig::class.java,
cobblemonResource("find_air") to FindAirTaskConfig::class.java,
cobblemonResource("go_to_land") to GoToLandTaskConfig::class.java
cobblemonResource("go_to_land") to GoToLandTaskConfig::class.java,
cobblemonResource("battle_flight_task") to BattleFlightTaskConfig::class.java
)
val runtime = MoLangRuntime().setup()
@@ -125,10 +125,11 @@ open class PartySelectPokemonDTO(
val heldItem: ItemStack = ItemStack.EMPTY,
var currentHealth: Int,
var maxHealth: Int,
var enabled: Boolean
var enabled: Boolean,
var hoverText: List<Component> = emptyList()
) {
@JvmOverloads
constructor(pokemon: Pokemon, enabled: Boolean = true): this(
constructor(pokemon: Pokemon, enabled: Boolean = true, hoverText: List<Component> = emptyList()): this(
pokemonProperties = pokemon.createPokemonProperties(
PokemonPropertyExtractor.SPECIES,
PokemonPropertyExtractor.LEVEL,
@@ -140,7 +141,8 @@ open class PartySelectPokemonDTO(
heldItem = pokemon.heldItemNoCopy(),
currentHealth = pokemon.currentHealth,
maxHealth = pokemon.maxHealth,
enabled = enabled
enabled = enabled,
hoverText = hoverText
)
constructor(buffer: RegistryFriendlyByteBuf): this(
@@ -149,7 +151,8 @@ open class PartySelectPokemonDTO(
heldItem = buffer.readItemStack(),
currentHealth = buffer.readInt(),
maxHealth = buffer.readInt(),
enabled = buffer.readBoolean()
enabled = buffer.readBoolean(),
hoverText = buffer.readList { buffer.readText() }
)
fun writeToBuffer(buffer: RegistryFriendlyByteBuf) {
@@ -159,6 +162,6 @@ open class PartySelectPokemonDTO(
buffer.writeInt(currentHealth)
buffer.writeInt(maxHealth)
buffer.writeBoolean(enabled)
buffer.writeCollection(hoverText) { _, text -> buffer.writeText(text) }
}
}
}
@@ -23,7 +23,8 @@ enum class Flavour(val colour: Int, val chatFormatting: ChatFormatting): StringR
DRY(0xFF0000, ChatFormatting.DARK_AQUA),
SWEET(0x0000FF, ChatFormatting.LIGHT_PURPLE),
BITTER(0xFFFF00, ChatFormatting.GREEN),
SOUR(0xFF00FF, ChatFormatting.YELLOW);
SOUR(0xFF00FF, ChatFormatting.YELLOW),
MILD(0xFF00FF, ChatFormatting.DARK_PURPLE);
override fun getSerializedName() = name
companion object {
@@ -29,9 +29,12 @@ private val bubbleColourMap = mapOf(
fun getColourMixFromSeasonings(seasonings: List<ItemStack>, forBubbles: Boolean = false): Int? {
val flavors = seasonings
.flatMap { Seasonings.getFlavoursFromItemStack(it).entries }
.groupingBy { it.key }
.fold(0) { acc, entry -> acc + entry.value }
.mapNotNull { Seasonings.getFlavoursFromItemStack(it) }
.flatMap { it.entries }
.groupingBy { it.key }
.fold(0) { acc, entry -> acc + entry.value }
if (flavors.isEmpty()) return null
val maxFlavorValue = flavors.values.maxOrNull()
val dominantFlavors = flavors.filter { it.value == maxFlavorValue }.map { it.key }
@@ -54,6 +57,25 @@ fun getColourMixFromFlavours(dominantFlavours: List<Flavour>, forBubbles: Boolea
acc
}
return FastColor.ARGB32.color(
alphaSum / colors.size,
redSum / colors.size,
greenSum / colors.size,
blueSum / colors.size
)
}
fun getColourMixFromColors(colors: List<Int>): Int? {
if (colors.isEmpty()) return null
val (alphaSum, redSum, greenSum, blueSum) = colors.fold(IntArray(4)) { acc, color ->
acc[0] += FastColor.ARGB32.alpha(color)
acc[1] += FastColor.ARGB32.red(color)
acc[2] += FastColor.ARGB32.green(color)
acc[3] += FastColor.ARGB32.blue(color)
acc
}
return FastColor.ARGB32.color(
alphaSum / colors.size,
redSum / colors.size,
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cooking
import com.cobblemon.mod.common.item.components.FoodComponent
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
data class Food(
val hunger: Int = 0,
val saturation: Float = 0f,
) {
companion object {
val CODEC: Codec<Food> = RecordCodecBuilder.create { builder ->
builder.group(
Codec.INT.optionalFieldOf("hunger", 0).forGetter { it.hunger },
Codec.FLOAT.optionalFieldOf("saturation", 0f).forGetter { it.saturation },
).apply(builder, ::Food)
}
}
fun toComponent(): FoodComponent = FoodComponent(hunger, saturation)
}
@@ -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.cooking
import com.cobblemon.mod.common.item.components.FoodComponent
import kotlin.math.ceil
import kotlin.math.round
object FoodUtils {
fun merge(components: List<FoodComponent>, extraHunger: Int = 0, extraSaturation: Float = 0f): FoodComponent {
if (components.isEmpty()) return FoodComponent(0, 0f)
val count = components.size
val totalHunger = components.sumOf { it.hunger.toDouble() } + extraHunger
val totalSaturation = components.sumOf { it.saturation.toDouble() } + extraSaturation
val multiplier = when (count) {
1 -> 1.0
2 -> 0.8
3 -> 0.6
else -> 0.4
}
val adjustedHunger = ceil(totalHunger * multiplier)
val adjustedSaturation = totalSaturation * multiplier
return FoodComponent(
hunger = adjustedHunger.toInt(),
saturation = (round(adjustedSaturation * 100) / 100f).toFloat()
)
}
}
@@ -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.cooking
import net.minecraft.world.effect.MobEffectInstance
import kotlin.math.ceil
import kotlin.math.max
object MobEffectUtils {
fun mergeEffects(effects: List<SerializableMobEffectInstance>): List<SerializableMobEffectInstance> {
val grouped = effects.groupBy { it.effect }
return grouped.map { (effectId, group) ->
val amplifier = mergeAmplifiers(group.map { it.amplifier })
val duration = mergeDurations(group.map { it.duration })
val first = group.first()
SerializableMobEffectInstance(
effect = effectId,
duration = duration,
amplifier = amplifier,
ambient = first.ambient,
visible = first.visible,
showIcon = first.showIcon
)
}
}
private fun mergeDurations(durations: List<Int>): Int {
if (durations.isEmpty()) return 0
val sorted = durations.sortedDescending()
var result = 0.0
for ((index, value) in sorted.withIndex()) {
val multiplier = when (index) {
0 -> 1.0
1 -> 0.75
2 -> 0.5
else -> 0.25
}
result += value * multiplier
}
return ceil(result).toInt()
}
private fun mergeAmplifiers(amplifiers: List<Int>): Int {
return amplifiers.maxOrNull() ?: 0 // we do not want the power of the effects to combine, just take the highest one used of that type
}
}
@@ -0,0 +1,95 @@
/*
* 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.cooking
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.item.PokePuffItem
import com.cobblemon.mod.common.item.PokePuffItem.Companion.DISLIKED_FLAVOR_MULTIPLIER
import com.cobblemon.mod.common.item.PokePuffItem.Companion.LIKED_FLAVOR_MULTIPLIER
import com.cobblemon.mod.common.pokemon.Nature
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.ItemStack
import net.minecraft.core.registries.BuiltInRegistries
object PokePuffUtils {
fun calculateFriendshipChange(stack: ItemStack, nature: Nature): Int {
val dominantFlavour = getDominantFlavour(stack) ?: return 0
val isNeutralNature = nature.favouriteFlavour == nature.dislikedFlavour
val (baseFriendship) = calculateBaseFriendship(stack)
return when {
dominantFlavour == nature.favouriteFlavour -> (baseFriendship / LIKED_FLAVOR_MULTIPLIER).toInt()
dominantFlavour == Flavour.MILD && isNeutralNature -> (baseFriendship / 2.0).coerceAtLeast(1.0).toInt()
else -> (-baseFriendship / DISLIKED_FLAVOR_MULTIPLIER).toInt()
}
}
fun calculateBaseFriendship(stack: ItemStack): Pair<Double, Double> {
val ingredientIds = stack.get(CobblemonItemComponents.INGREDIENT)?.ingredientIds ?: emptyList()
var baseFriendship = 0.0
for (id in ingredientIds) {
val item = BuiltInRegistries.ITEM.get(id)
val itemStack = ItemStack(item)
val seasoning = Seasonings.getFromItemStack(itemStack) ?: continue
val dominantValue = seasoning.flavours?.values?.maxOrNull() ?: 0
baseFriendship += dominantValue
}
val ingredientStrings = ingredientIds.map { it.toString() }
val hasSugar = "minecraft:sugar" in ingredientStrings
val hasSweet = ingredientStrings.any { it.startsWith("cobblemon:") && it.endsWith("_sweet") }
val multiplier = when {
hasSugar && hasSweet -> 5.0
hasSweet -> 2.25
hasSugar -> 1.75
else -> 1.0
}
val finalBaseFriendship = baseFriendship * multiplier
return finalBaseFriendship to multiplier
}
fun getDominantFlavour(stack: ItemStack): Flavour? {
val flavours = stack.get(CobblemonItemComponents.FLAVOUR)?.flavours ?: return null
val max = flavours.values.maxOrNull() ?: return null
val dominant = flavours.filterValues { it == max }.keys
return when {
dominant.isEmpty() -> null
dominant.size > 1 -> Flavour.MILD
else -> dominant.first()
}
}
fun getFlavorNatureLabel(flavour: Flavour): String {
return when (flavour) {
Flavour.SPICY -> "attack"
Flavour.DRY -> "special_attack"
Flavour.SWEET -> "speed"
Flavour.BITTER -> "special_defense"
Flavour.SOUR -> "defense"
Flavour.MILD -> "neutral"
}
}
fun getFriendshipChangeLiked(stack: ItemStack): Int {
val (baseFriendship) = calculateBaseFriendship(stack)
return (baseFriendship / LIKED_FLAVOR_MULTIPLIER).toInt()
}
fun getFriendshipChangeDisliked(stack: ItemStack): Int {
val (baseFriendship) = calculateBaseFriendship(stack)
return (baseFriendship / DISLIKED_FLAVOR_MULTIPLIER).toInt()
}
}
@@ -21,33 +21,43 @@ import net.minecraft.network.codec.ByteBufCodecs
import net.minecraft.network.codec.StreamCodec
import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.Item
import java.util.Optional
import kotlin.jvm.optionals.getOrNull
data class Seasoning(
val ingredient: RegistryLikeCondition<Item>,
@SerializedName("flavours", alternate = ["flavors"])
val flavours: Map<Flavour, Int>,
val flavours: Map<Flavour, Int>? = null,
@SerializedName("colour", alternate = ["color"])
val colour: DyeColor,
@SerializedName("baitEffects")
val baitEffects: List<SpawnBait.Effect> = emptyList()
val baitEffects: List<SpawnBait.Effect>? = null,
@SerializedName("food")
val food: Food? = null,
@SerializedName("mobEffects")
val mobEffects: List<SerializableMobEffectInstance>? = null
) {
companion object {
val CODEC: Codec<Seasoning> = RecordCodecBuilder.create { builder ->
builder.group(
ITEM_REGISTRY_LIKE_CODEC.fieldOf("ingredient").forGetter { it.ingredient },
Codec.unboundedMap(Flavour.CODEC, Codec.INT).fieldOf("flavours").forGetter { it.flavours }, // Use map codec
Codec.unboundedMap(Flavour.CODEC, Codec.INT).optionalFieldOf("flavours").forGetter { Optional.ofNullable(it.flavours) },
DyeColor.CODEC.fieldOf("colour").forGetter { it.colour },
SpawnBait.Effect.CODEC.listOf().optionalFieldOf("baitEffects", emptyList()).forGetter { it.baitEffects }
).apply(builder, ::Seasoning)
SpawnBait.Effect.CODEC.listOf().optionalFieldOf("baitEffects").forGetter { Optional.ofNullable(it.baitEffects) },
Food.CODEC.optionalFieldOf("food").forGetter { Optional.ofNullable(it.food) },
SerializableMobEffectInstance.CODEC.listOf().optionalFieldOf("mobEffects").forGetter { Optional.ofNullable(it.mobEffects) }
).apply(builder) { item, flavours, colour, baitEffects, food, mobEffects ->
Seasoning(
item,
flavours.getOrNull(),
colour,
baitEffects.getOrNull(),
food.getOrNull(),
mobEffects.getOrNull()
)
}
}
val STREAM_CODEC: StreamCodec<ByteBuf, Seasoning> = ByteBufCodecs.fromCodec(CODEC)
val BLANK_SEASONING = Seasoning(
ingredient = RegistryLikeIdentifierCondition<Item>(cobblemonResource("blank")),
flavours = Flavour.entries.associate { it to 0 },
colour = DyeColor.WHITE,
baitEffects = emptyList()
)
}
}
@@ -14,7 +14,10 @@ import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
import com.cobblemon.mod.common.api.conditional.RegistryLikeIdentifierCondition
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.fishing.SpawnBait
import com.cobblemon.mod.common.api.fishing.SpawnBaitEffects
import com.cobblemon.mod.common.api.fishing.SpawnBaitUtils
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.item.components.FoodComponent
import com.cobblemon.mod.common.net.messages.client.cooking.SeasoningRegistrySyncPacket
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.ItemLikeConditionAdapter
@@ -43,12 +46,6 @@ object Seasonings : JsonDataRegistry<Seasoning> {
val seasonings = mutableListOf<Seasoning>()
val BLANK_SEASONING = Seasoning(
ingredient = RegistryLikeIdentifierCondition<Item>(cobblemonResource("blank")),
flavours = emptyMap(),
colour = DyeColor.WHITE
)
override fun sync(player: ServerPlayer) {
SeasoningRegistrySyncPacket(seasonings.toList()).sendToPlayer(player)
}
@@ -59,7 +56,10 @@ object Seasonings : JsonDataRegistry<Seasoning> {
it.identifier to Seasoning(
ingredient = RegistryLikeIdentifierCondition(it.identifier),
flavours = it.flavours.toMap(),
colour = it.colour
colour = it.colour,
baitEffects = emptyList(),
food = Food(),
mobEffects = emptyList()
)
}.toMutableMap()
finalData.putAll(data)
@@ -71,16 +71,54 @@ object Seasonings : JsonDataRegistry<Seasoning> {
this.seasonings.addAll(seasonings)
}
fun getFlavoursFromItemStack(stack: ItemStack): Map<Flavour, Int> {
fun getFlavoursFromItemStack(stack: ItemStack): Map<Flavour, Int>? {
val holder = stack.itemHolder
val seasoning = seasonings.find { it.ingredient.fits(holder) } ?: BLANK_SEASONING
val inherentFlavours = stack.get(CobblemonItemComponents.FLAVOUR)?.flavours ?: emptyMap()
val seasoning = seasonings.find { it.ingredient.fits(holder) }
val inherentFlavours = stack.get(CobblemonItemComponents.FLAVOUR)?.flavours
val seasoningFlavours = seasoning?.flavours
return seasoning.flavours.mapValues { (flavour, value) -> inherentFlavours.getOrDefault(flavour, 0) + value }
if (seasoningFlavours.isNullOrEmpty() && inherentFlavours.isNullOrEmpty())
return null
return (seasoningFlavours ?: emptyMap()).mapValues { (flavour, value) ->
value + (inherentFlavours?.getOrDefault(flavour, 0) ?: 0)
}
}
fun hasFlavors(stack: ItemStack): Boolean {
val flavors = getFlavoursFromItemStack(stack)
return !flavors.isNullOrEmpty() && flavors.any { it.value != 0 }
}
fun getFoodComponentFromItemStack(stack: ItemStack): FoodComponent? {
return getFromItemStack(stack)?.food?.toComponent()
}
fun hasFood(stack: ItemStack): Boolean {
val effects = getFromItemStack(stack)?.food ?: return false
return effects.hunger > 0 || effects.saturation > 0f
}
fun getMobEffectsFromItemStack(stack: ItemStack): List<SerializableMobEffectInstance> {
return getFromItemStack(stack)?.mobEffects ?: emptyList()
}
fun hasMobEffect(stack: ItemStack): Boolean {
return !getFromItemStack(stack)?.mobEffects.isNullOrEmpty()
}
fun getBaitEffectsFromItemStack(stack: ItemStack): List<SpawnBait.Effect> {
return getFromItemStack(stack)?.baitEffects ?: emptyList()
val primaryEffects = SpawnBaitEffects.getEffectsFromItemStack(stack)
return if (primaryEffects.isNotEmpty()) {
primaryEffects
} else {
getFromItemStack(stack)?.baitEffects ?: emptyList()
}
}
fun hasBaitEffects(stack: ItemStack): Boolean {
return SpawnBaitEffects.getEffectsFromItemStack(stack).isNotEmpty() ||
!(getFromItemStack(stack)?.baitEffects.isNullOrEmpty())
}
fun getFromItemStack(stack: ItemStack): Seasoning? {
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cooking
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.core.Holder
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.effect.MobEffect
import net.minecraft.world.effect.MobEffectInstance
data class SerializableMobEffectInstance(
val effect: ResourceLocation,
val duration: Int,
val amplifier: Int = 0,
val ambient: Boolean = false,
val visible: Boolean = true,
val showIcon: Boolean = true
) {
fun toInstance(): MobEffectInstance {
val holder = BuiltInRegistries.MOB_EFFECT.getHolder(effect)
.orElseThrow { IllegalArgumentException("Unknown MobEffect: $effect") }
return MobEffectInstance(holder, duration, amplifier, ambient, visible, showIcon)
}
companion object {
val CODEC: Codec<SerializableMobEffectInstance> = RecordCodecBuilder.create { builder ->
builder.group(
ResourceLocation.CODEC.fieldOf("effect").forGetter { it.effect },
Codec.INT.fieldOf("duration").forGetter { it.duration },
Codec.INT.fieldOf("amplifier").forGetter { it.amplifier },
Codec.BOOL.optionalFieldOf("ambient", false).forGetter { it.ambient },
Codec.BOOL.optionalFieldOf("visible", true).forGetter { it.visible },
Codec.BOOL.optionalFieldOf("showIcon", true).forGetter { it.showIcon }
).apply(builder, ::SerializableMobEffectInstance)
}
}
}
@@ -24,6 +24,7 @@ sealed interface DialogueFaceProvider {
companion object {
val types = mutableMapOf(
"artificial" to ArtificialDialogueFaceProvider::class.java,
"player" to PlayerDialogueFaceProvider::class.java,
"standard" to ArtificialDialogueFaceProvider::class.java,
"expression" to ExpressionLikeDialogueFaceProvider::class.java
@@ -25,6 +25,7 @@ import com.cobblemon.mod.common.api.events.drops.LootDroppedEvent
import com.cobblemon.mod.common.api.events.entity.PokemonEntityLoadEvent
import com.cobblemon.mod.common.api.events.entity.PokemonEntitySaveEvent
import com.cobblemon.mod.common.api.events.entity.PokemonEntitySaveToWorldEvent
import com.cobblemon.mod.common.api.events.entity.SpawnBucketChosenEvent
import com.cobblemon.mod.common.api.events.entity.SpawnEvent
import com.cobblemon.mod.common.api.events.farming.ApricornHarvestEvent
import com.cobblemon.mod.common.api.events.fishing.*
@@ -71,6 +72,8 @@ object CobblemonEvents {
@JvmField
val FRIENDSHIP_UPDATED = EventObservable<FriendshipUpdatedEvent>()
@JvmField
val FULLNESS_UPDATED = EventObservable<FullnessUpdatedEvent>()
@JvmField
val POKEMON_FAINTED = EventObservable<PokemonFaintedEvent>()
@JvmField
val EVOLUTION_ACCEPTED = CancelableObservable<EvolutionAcceptedEvent>()
@@ -168,6 +171,11 @@ object CobblemonEvents {
@JvmField
val EV_GAINED_EVENT_POST = EventObservable<EvGainedEvent.Post>()
@JvmField
val HYPER_TRAINED_IV_PRE = CancelableObservable<HyperTrainedIvEvent.Pre>()
@JvmField
val HYPER_TRAINED_IV_POST = EventObservable<HyperTrainedIvEvent.Post>()
@JvmField
val POKEMON_RELEASED_EVENT_PRE = CancelableObservable<ReleasePokemonEvent.Pre>()
@JvmField
@@ -245,8 +253,6 @@ object CobblemonEvents {
@JvmField
val POKEROD_REEL = CancelableObservable<PokerodReelEvent>()
@JvmField
val BOBBER_BUCKET_CHOSEN = EventObservable<BobberBucketChosenEvent>()
@JvmField
val BOBBER_SPAWN_POKEMON_PRE = CancelableObservable<BobberSpawnPokemonEvent.Pre>()
@JvmField
val BOBBER_SPAWN_POKEMON_MODIFY = EventObservable<BobberSpawnPokemonEvent.Modify>()
@@ -255,6 +261,9 @@ object CobblemonEvents {
@JvmField
val BAIT_EFFECT_REGISTRATION = EventObservable<BaitEffectFunctionRegistryEvent>()
@JvmField
val SPAWN_BUCKET_CHOSEN = EventObservable<SpawnBucketChosenEvent>()
// Baits and Lures
@JvmField
val BAIT_SPAWN_POKEMON_MODIFY = EventObservable<BaitSpawnPokemonEvent.Modify>()
@@ -0,0 +1,27 @@
/*
* 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.entity
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.SpawnCause
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
/**
* Event fired when the spawning system makes a decision on which bucket to spawn from.
*/
class SpawnBucketChosenEvent(
/** The spawner this is happening within. */
val spawner: Spawner,
/** The cause of the spawn. */
val spawnCause: SpawnCause,
/** The bucket that was chosen. You can alter this. */
var bucket: SpawnBucket,
/** The final weights that were used to make the choice. */
val bucketWeights: Map<SpawnBucket, Float>
)
@@ -10,15 +10,15 @@ package com.cobblemon.mod.common.api.events.entity
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.api.spawning.BestSpawner
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import net.minecraft.world.entity.Entity
/**
* Event fired when an entity is spawned using the [BestSpawner]. The entity that was spawned
* and the [SpawningContext] of the spawn are provided. Cancelling this event will prevent the
* and the [SpawnablePosition] of the spawn are provided. Cancelling this event will prevent the
* entity from spawning.
*
* @author Hiroku
* @since April 22nd, 2023
*/
class SpawnEvent<T : Entity>(val entity: T, val ctx: SpawningContext) : Cancelable()
class SpawnEvent<T : Entity>(val entity: T, val spawnablePosition: SpawnablePosition) : Cancelable()
@@ -8,12 +8,12 @@
package com.cobblemon.mod.common.api.events.fishing
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.ObjectValue
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.itemRegistry
@@ -28,23 +28,23 @@ interface BobberSpawnPokemonEvent {
/**
* Event that is fired before a Pokemon is spawned by a bobber.
* @param bobber The PokeRodFishingBobberEntity that is spawning the Pokemon.
* @param chosenBucket The bucket that is chosen.
* @param spawnAction The spawn that is planned.
* @param rod The ItemStack of the rod that the bobber is attached to.
*/
data class Pre(
val bobber: PokeRodFishingBobberEntity,
val chosenBucket: SpawnBucket,
val spawnAction: SpawnAction<*>,
val rod: ItemStack
) : Cancelable(), BobberSpawnPokemonEvent
/**
* Event that is fired when a Pokemon is modified before it is spawned by a bobber.
* @param chosenBucket The bucket that is chosen.
* @param spawnAction The [SpawnAction] that is motivating the spawn.
* @param rod The ItemStack of the rod that the bobber is attached to.
* @param pokemon The Pokemon that is modified.
*/
data class Modify(
val chosenBucket: SpawnBucket,
val spawnAction: SpawnAction<*>,
val rod: ItemStack,
val pokemon: PokemonEntity
) : BobberSpawnPokemonEvent
@@ -58,12 +58,12 @@ interface BobberSpawnPokemonEvent {
*/
data class Post(
val bobber: PokeRodFishingBobberEntity,
val chosenBucket: SpawnBucket,
val spawnAction: SpawnAction<*>,
val bait: ItemStack,
val pokemon: PokemonEntity
) : BobberSpawnPokemonEvent {
val context = mutableMapOf<String, MoValue>(
"chosen_bucket" to ObjectValue(chosenBucket, { it.name }),
"chosen_bucket" to ObjectValue(spawnAction.bucket, { it.name }),
"bait" to pokemon.level().itemRegistry.wrapAsHolder(bait.item).asMoLangValue(Registries.ITEM),
"pokemon_entity" to pokemon.asMoLangValue()
)
@@ -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.events.pokemon
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.pokemon.Pokemon
/**
* Event that is fired when a player owned Pokémon has its fullness changed
*/
data class FullnessUpdatedEvent(
val pokemon: Pokemon,
val newFullnessInitial: Int
) {
var newFullness: Int = newFullnessInitial
set(value) {
field = value.coerceIn(0, pokemon.getMaxFullness())
}
}
@@ -0,0 +1,58 @@
/*
* 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.pokemon
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.api.pokemon.stats.Stat
import com.cobblemon.mod.common.pokemon.Pokemon
/**
* Fired during a Hyper Training mutation.
*
* @see [Pre]
* @see [Post]
*/
interface HyperTrainedIvEvent {
/**
* The [Stat] having whose IV is being hyper-trained.
*/
val stat: Stat
/**
* The [Pokemon] being hyper-trained.
*/
val pokemon: Pokemon
/**
* Fired before Hyper Training occurs, cancelling will cause the mutation to be flagged as not successful.
*/
class Pre(override val pokemon: Pokemon, override val stat: Stat, var value: Int) : HyperTrainedIvEvent, Cancelable() {
val context = mutableMapOf(
"pokemon" to pokemon.struct,
"stat" to StringValue(stat.toString()),
"value" to DoubleValue(value)
)
val functions = moLangFunctionMap(cancelFunc)
}
/**
* Fired after Hyper Training occurs, this is purely for notification purposes.
*/
class Post(override val pokemon: Pokemon, override val stat: Stat, val value: Int) : HyperTrainedIvEvent {
val context = mutableMapOf(
"pokemon" to pokemon.struct,
"stat" to StringValue(stat.toString()),
"value" to DoubleValue(value)
)
}
}
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.api.fishing
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
import com.cobblemon.mod.common.api.conditional.RegistryLikeIdentifierCondition
import com.cobblemon.mod.common.api.cooking.Seasonings
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.SpawnBaitRegistrySyncPacket
@@ -85,7 +86,7 @@ object SpawnBaitEffects : JsonDataRegistry<SpawnBait> {
(it.ingredient as RegistryLikeIdentifierCondition<Item>).identifier.path == identifier.path
}
if (seasoning != null && seasoning.baitEffects.isNotEmpty()) {
if (seasoning != null && !seasoning.baitEffects.isNullOrEmpty()) {
return SpawnBait(
item = seasoning.ingredient,
effects = seasoning.baitEffects
@@ -96,8 +97,9 @@ object SpawnBaitEffects : JsonDataRegistry<SpawnBait> {
return null
}
// if it has bait effects and is not listed as a seasoning then it is a bait
fun isFishingBait(stack: ItemStack): Boolean {
val holder = stack.itemHolder
return stack.has(CobblemonItemComponents.BAIT_EFFECTS) || effectsMap.values.any { it.item.fits(holder) }
return effectsMap.values.any { it.item.fits(holder) }
}
}
@@ -8,6 +8,8 @@
package com.cobblemon.mod.common.api.fishing
import kotlin.math.ceil
object SpawnBaitUtils {
fun mergeEffects(effects: List<SpawnBait.Effect>): List<SpawnBait.Effect> {
val grouped = effects.groupBy { Pair(it.type, it.subcategory) }
@@ -15,25 +17,20 @@ object SpawnBaitUtils {
return grouped.map { (key, groupEffects) ->
val (type, subcategory) = key
if (type == SpawnBait.Effects.RARITY_BUCKET) {
// we want to keep the highest rarity bucket effect instead of merging them
groupEffects.maxByOrNull { it.value }!!
} else {
val count = groupEffects.size
val totalChance = groupEffects.sumOf { it.chance }
val totalValue = groupEffects.sumOf { it.value }
val count = groupEffects.size
val totalChance = groupEffects.sumOf { it.chance }
val totalValue = groupEffects.sumOf { it.value }
val multiplier = when (count) {
2 -> 0.8
3 -> 0.9
else -> 1.0
}
val adjustedChance = (totalChance * multiplier).coerceAtMost(1.0)
val adjustedValue = totalValue * multiplier
SpawnBait.Effect(type, subcategory, adjustedChance, adjustedValue)
val multiplier = when (count) {
2 -> 0.8
3 -> 0.6
else -> 1.0
}
val adjustedChance = (totalChance * multiplier).coerceAtMost(1.0)
val adjustedValue = ceil(totalValue * multiplier)
SpawnBait.Effect(type, subcategory, adjustedChance, adjustedValue)
}
}
}
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
import com.cobblemon.mod.common.api.callback.MoveSelectCallbacks
import com.cobblemon.mod.common.api.callback.PartyMoveSelectCallbacks
import com.cobblemon.mod.common.api.moves.Move
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.battles.BagItemActionResponse
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
@@ -92,7 +93,13 @@ interface PokemonAndMoveSelectingItem {
}
}
fun canUseOnPokemon(stack: ItemStack, pokemon: Pokemon): Boolean
fun canUseOnPokemon(stack: ItemStack, pokemon: Pokemon): Boolean {
if (stack.`is`(CobblemonItemTags.POKE_FOOD)) {
return !pokemon.isFull()
}
return true
}
fun canUseOnBattlePokemon(stack: ItemStack, battlePokemon: BattlePokemon): Boolean = bagItem!!.canUse(stack, battlePokemon.actor.battle, battlePokemon)
fun canUseOnMove(stack: ItemStack, pokemon: Pokemon, move: Move): Boolean = canUseOnMove(stack, move)
fun canUseOnMove(stack: ItemStack, move: Move): Boolean
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.advancement.CobblemonCriteria
import com.cobblemon.mod.common.advancement.criterion.PokemonInteractContext
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
import com.cobblemon.mod.common.api.callback.PartySelectCallbacks
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.battles.BagItemActionResponse
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
@@ -105,7 +106,13 @@ interface PokemonSelectingItem {
}
}
fun canUseOnPokemon(stack: ItemStack, pokemon: Pokemon): Boolean
fun canUseOnPokemon(stack: ItemStack, pokemon: Pokemon): Boolean {
if (stack.`is`(CobblemonItemTags.POKE_FOOD)) {
return !pokemon.isFull()
}
return true
}
fun canUseOnBattlePokemon(stack: ItemStack, battlePokemon: BattlePokemon): Boolean = bagItem!!.canUse(stack, battlePokemon.actor.battle, battlePokemon)
fun interactWithSpecificBattle(player: ServerPlayer, stack: ItemStack, battlePokemon: BattlePokemon): InteractionResultHolder<ItemStack> {
@@ -136,6 +143,7 @@ interface PokemonSelectingItem {
}
)
return InteractionResultHolder.success(stack)
}
@@ -22,6 +22,7 @@ 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.Environment
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
@@ -32,6 +33,7 @@ import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
import com.cobblemon.mod.common.api.moves.animations.NPCProvider
import com.cobblemon.mod.common.api.npc.NPCClasses
import com.cobblemon.mod.common.api.npc.configuration.interaction.DialogueNPCInteractionConfiguration
import com.cobblemon.mod.common.api.npc.configuration.interaction.ScriptNPCInteractionConfiguration
import com.cobblemon.mod.common.api.npc.partyproviders.SimplePartyProvider
import com.cobblemon.mod.common.api.pokedex.AbstractPokedexManager
@@ -44,8 +46,11 @@ 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.scheduling.ClientTaskTracker
import com.cobblemon.mod.common.api.scheduling.Schedulable
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import com.cobblemon.mod.common.api.storage.PokemonStore
import com.cobblemon.mod.common.api.storage.party.NPCPartyStore
import com.cobblemon.mod.common.api.storage.party.PartyStore
@@ -68,7 +73,9 @@ 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.net.messages.client.sound.UnvalidatedPlaySoundS2CPacket
import com.cobblemon.mod.common.pokemon.Gender
import com.cobblemon.mod.common.pokemon.IVs
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
@@ -96,6 +103,7 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.server.MinecraftServer
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundSource
import net.minecraft.tags.TagKey
import net.minecraft.world.damagesource.DamageSource
import net.minecraft.world.damagesource.DamageTypes
@@ -197,7 +205,15 @@ object MoLangFunctions {
runtime.environment.variable = params.environment.variable
runtime.environment.context = params.environment.context
val expression = params.getString(0).asExpressionLike()
runtime.resolve(expression)
val delayInSeconds = params.getDoubleOrNull(1)?.toFloat() ?: 0.0f
if (delayInSeconds > 0.0f) {
val tracker = if (Cobblemon.implementation.environment() == Environment.SERVER) ServerTaskTracker else ClientTaskTracker
tracker.after(delayInSeconds) {
runtime.resolve(expression)
}
} else {
runtime.resolve(expression)
}
},
"system_time_millis" to java.util.function.Function { _ ->
DoubleValue(System.currentTimeMillis())
@@ -344,6 +360,27 @@ object MoLangFunctions {
return@put DoubleValue.ZERO
}
}
map.put("play_sound_on_server") { params ->
val sound = params.getString(0).asResource()
val soundSource = params.getString(1).uppercase()
val x = params.getDouble(2)
val y = params.getDouble(3)
val z = params.getDouble(4)
val player = params.getOrNull<MoValue>(5)?.let {
if (it is StringValue) world.getPlayerByUUID(UUID.fromString(it.value))
else if (it is ObjectValue<*>) it.obj
else null
} as? ServerPlayer
val volume = params.getDoubleOrNull(6)?.toFloat() ?: 1.0f
val pitch = params.getDoubleOrNull(7)?.toFloat() ?: 1.0f
val packet = UnvalidatedPlaySoundS2CPacket(sound, SoundSource.valueOf(soundSource), x, y, z, volume, pitch)
if (player != null) {
packet.sendToPlayer(player)
} else {
packet.sendToPlayersAround(x, y, z, 16.0, world.dimension())
}
}
map.put("get_entities_around") { params ->
val x = params.getDouble(0)
val y = params.getDouble(1)
@@ -404,6 +441,15 @@ object MoLangFunctions {
val command = params.getString(0)
player.server.commands.performPrefixedCommand(player.createCommandSourceStack(), command)
}
map.put("play_sound_on_server") { params ->
val sound = params.getString(0).asResource()
val soundSource = SoundSource.valueOf(params.getString(1).uppercase())
val volume = params.getDoubleOrNull(2)?.toFloat() ?: 1.0f
val pitch = params.getDoubleOrNull(3)?.toFloat() ?: 1.0f
val packet = UnvalidatedPlaySoundS2CPacket(sound, soundSource, player.x, player.y, player.z, volume, pitch)
packet.sendToPlayer(player)
}
map.put("is_party_at_full_health") { _ ->
DoubleValue(player.party().none(Pokemon::canBeHealed)) }
map.put("can_heal_at_healer") { params ->
@@ -618,8 +664,9 @@ object MoLangFunctions {
map.put("biome") { _ -> entity.level().getBiome(entity.blockPosition()).asBiomeMoLangValue() }
map.put("is_passenger") { DoubleValue(entity.isPassenger) }
map.put("find_nearby_block") { params ->
val type = params.getString(0).asIdentifierDefaultingNamespace(namespace = "minecraft")
val isTag = type.path.startsWith("#")
val input = params.getString(0)
val isTag = input.contains("#")
val type = input.replace("#", "").asIdentifierDefaultingNamespace(namespace = "minecraft")
val range = params.getDoubleOrNull(1) ?: 10
val blockPos = entity.level().getBlockStatesWithPos(AABB.ofSize(entity.position(), range.toDouble(), range.toDouble(), range.toDouble()))
.filter { it.first.blockHolder.let { if (isTag) it.`is`(TagKey.create(Registries.BLOCK, type)) else it.`is`(type) } }
@@ -675,6 +722,17 @@ object MoLangFunctions {
}
}
}
if (entity is Schedulable) {
map.put("run_molang_after") { params ->
val expression = params.getString(0).asExpressionLike()
val delayInSeconds = params.getDouble(1).toFloat()
val runtime = MoLangRuntime()
runtime.environment.cloneFrom(params.environment)
entity.after(delayInSeconds) {
runtime.resolve(expression)
}
}
}
// q.entity.spawn_bedrock_particles(effect, locator, [player]) - sends to everyone nearby or just to the player if they're set. Locator is necessary even if unused on non-posables.
map.put("spawn_bedrock_particles") { params ->
val particle = params.getString(0).asResource()
@@ -811,6 +869,17 @@ object MoLangFunctions {
npc.hideNameTag = !nameTagVisible
return@put DoubleValue.ONE
}
map.put("unset_interaction") {
npc.interaction = null
return@put DoubleValue.ONE
}
map.put("set_dialogue_interaction") { params ->
val dialogue = params.getString(0).asIdentifierDefaultingNamespace()
npc.interaction = DialogueNPCInteractionConfiguration().also {
it.dialogue = dialogue
}
return@put DoubleValue.ONE
}
map.put("set_script_interaction") { params ->
val script = params.getString(0).asIdentifierDefaultingNamespace()
npc.interaction = ScriptNPCInteractionConfiguration().also {
@@ -1035,6 +1104,19 @@ object MoLangFunctions {
map.put("apply_potential_marks") {
return@put DoubleValue(pokemon.applyPotentialMarks())
}
map.put("hyper_train_iv") { params ->
val statId = params.getString(0)
val stat = Stats.getStat(statId)
val value = params.getIntOrNull(1) ?: IVs.MAX_VALUE
if (Stats.PERMANENT.contains(stat)) {
pokemon.hyperTrainIV(stat, value)
return@put DoubleValue.ONE
} else {
Cobblemon.LOGGER.error("Unknown or non-permanent stat: ${stat.toString()}")
return@put DoubleValue.ZERO
}
}
map
}
)
@@ -1184,7 +1266,7 @@ object MoLangFunctions {
}
)
val spawningContextFunctions = mutableListOf<(SpawningContext) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
val spawningContextFunctions = mutableListOf<(SpawnablePosition) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
{ spawningContext ->
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
val worldValue = spawningContext.world.registryAccess().registryOrThrow(Registries.DIMENSION).wrapAsHolder(spawningContext.world).asWorldMoLangValue()
@@ -1198,7 +1280,6 @@ object MoLangFunctions {
map.put("moon_phase") { _ -> DoubleValue(spawningContext.moonPhase.toDouble()) }
map.put("can_see_sky") { _ -> DoubleValue(spawningContext.canSeeSky) }
map.put("sky_light") { _ -> DoubleValue(spawningContext.skyLight.toDouble()) }
map.put("bucket") { _ -> StringValue(spawningContext.cause.bucket.name) }
map.put("player") { _ ->
val causeEntity = spawningContext.cause.entity ?: return@put DoubleValue.ZERO
if (causeEntity is ServerPlayer) {
@@ -1335,6 +1416,8 @@ object MoLangFunctions {
map.put("hitbox_height") { DoubleValue(species.hitbox.height) }
map.put("hitbox_fixed") { DoubleValue(species.hitbox.fixed) }
map.put("catch_rate") { DoubleValue(species.catchRate) }
map.put("labels") { return@put species.labels.asArrayValue { StringValue(it) } }
map.put("has_label") { params -> DoubleValue(species.labels.contains(params.getString(0))) }
map
}
)
@@ -1536,7 +1619,7 @@ object MoLangFunctions {
return value
}
fun SpawningContext.asMoLangValue(): ObjectValue<SpawningContext> {
fun SpawnablePosition.asMoLangValue(): ObjectValue<SpawnablePosition> {
val value = ObjectValue(
obj = this,
stringify = { it.toString() }
@@ -0,0 +1,56 @@
/*
* 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.moves
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.types.ElementalType
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.pokemon.Pokemon
object HiddenPowerUtil {
val hiddenPowerTable = arrayOf(
ElementalTypes.FIGHTING,
ElementalTypes.FLYING,
ElementalTypes.POISON,
ElementalTypes.GROUND,
ElementalTypes.ROCK,
ElementalTypes.BUG,
ElementalTypes.GHOST,
ElementalTypes.STEEL,
ElementalTypes.FIRE,
ElementalTypes.WATER,
ElementalTypes.GRASS,
ElementalTypes.ELECTRIC,
ElementalTypes.PSYCHIC,
ElementalTypes.ICE,
ElementalTypes.DRAGON,
ElementalTypes.DARK
)
fun getHiddenPowerType(pokemon: Pokemon?): ElementalType {
if (pokemon == null) {
return ElementalTypes.NORMAL
}
val ivs = pokemon.ivs
val ivArray = arrayOf(
ivs[Stats.HP],
ivs[Stats.ATTACK],
ivs[Stats.DEFENCE],
ivs[Stats.SPEED],
ivs[Stats.SPECIAL_ATTACK],
ivs[Stats.SPECIAL_DEFENCE]
).map { it ?: return@getHiddenPowerType ElementalTypes.NORMAL }
var tableIndex = 0
ivArray.forEachIndexed { index, it ->
tableIndex += (it % 2) shl index
}
tableIndex = tableIndex * 15 / 63
return hiddenPowerTable[tableIndex.coerceAtMost(hiddenPowerTable.size - 1)]
}
}
@@ -15,7 +15,6 @@ import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
import com.cobblemon.mod.common.api.moves.categories.DamageCategory
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.types.ElementalType
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.battles.MoveTarget
@@ -100,24 +99,6 @@ open class MoveTemplate(
Moves::getByName,
MoveTemplate::name
) { id -> "No MoveTemplate for ID $id" }
val hiddenPowerTable = arrayOf(
ElementalTypes.FIGHTING,
ElementalTypes.FLYING,
ElementalTypes.POISON,
ElementalTypes.GROUND,
ElementalTypes.ROCK,
ElementalTypes.BUG,
ElementalTypes.GHOST,
ElementalTypes.STEEL,
ElementalTypes.FIRE,
ElementalTypes.WATER,
ElementalTypes.GRASS,
ElementalTypes.ELECTRIC,
ElementalTypes.PSYCHIC,
ElementalTypes.ICE,
ElementalTypes.DRAGON,
ElementalTypes.DARK
)
}
/**
@@ -146,21 +127,7 @@ open class MoveTemplate(
return this.elementalType
}
if (name == "hiddenpower") {
val ivs = pokemon.ivs
val ivArray = arrayOf(
ivs[Stats.HP],
ivs[Stats.ATTACK],
ivs[Stats.DEFENCE],
ivs[Stats.SPEED],
ivs[Stats.SPECIAL_ATTACK],
ivs[Stats.SPECIAL_DEFENCE]
).map { it ?: return@getEffectiveElementalType ElementalTypes.NORMAL }
var tableIndex = 0
ivArray.forEachIndexed { index, it ->
tableIndex += (it % 2) shl index
}
tableIndex = tableIndex * 15 / 63
return hiddenPowerTable[tableIndex.coerceAtMost(hiddenPowerTable.size - 1)]
return HiddenPowerUtil.getHiddenPowerType(pokemon)
}
// TODO: Handle ability suppression: clientactivebattlepokemon needs data about volatiles
// TODO: Handle Liquid Voice: need to know what moves have the sound flag
@@ -16,7 +16,6 @@ import com.cobblemon.mod.common.api.moves.animations.UsersProvider
import com.cobblemon.mod.common.api.scheduling.after
import com.cobblemon.mod.common.entity.ai.OmniPathNavigation.NavigationContext
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.PokemonNavigation
import com.cobblemon.mod.common.util.asExpressionLike
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.phys.Vec3
@@ -96,6 +96,8 @@ object CobblemonPermissions {
@JvmStatic
val PC = this.create("${COMMAND_PREFIX}pc", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val PC_SEARCH = this.create("${COMMAND_PREFIX}pcsearch", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
val POKEBOX = this.create("${COMMAND_PREFIX}pokebox", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.api.pokemon
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.Cobblemon.config
import com.cobblemon.mod.common.api.abilities.Abilities
import com.cobblemon.mod.common.api.abilities.Ability
import com.cobblemon.mod.common.api.events.CobblemonEvents
@@ -42,6 +43,7 @@ import com.google.gson.JsonArray
import com.google.gson.JsonObject
import com.mojang.brigadier.StringReader
import com.mojang.serialization.Codec
import com.mojang.serialization.JsonOps
import java.util.UUID
import kotlin.math.min
import kotlin.random.Random
@@ -50,6 +52,7 @@ import net.minecraft.commands.arguments.item.ItemParser
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.nbt.NbtOps
import net.minecraft.nbt.StringTag
import net.minecraft.nbt.Tag
import net.minecraft.network.chat.Component
@@ -58,6 +61,7 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level
import kotlin.jvm.optionals.getOrNull
/**
* A grouping of typical, selectable properties for a Pokémon. This is serializable
@@ -385,7 +389,13 @@ open class PokemonProperties {
shiny?.let { pokemon.shiny = it }
gender?.let { pokemon.gender = it }
level?.let { pokemon.level = it }
friendship?.let { pokemon.setFriendship(it) }
friendship.also {
if (it != null) {
pokemon.setFriendship(it)
} else {
pokemon.setFriendship(pokemon.form.baseFriendship)
}
}
pokeball?.let { PokeBalls.getPokeBall(it.asIdentifierDefaultingNamespace())?.let { pokeball -> pokemon.caughtBall = pokeball } }
nature?.let { Natures.getNature(it.asIdentifierDefaultingNamespace())?.let { nature -> pokemon.nature = nature } }
ability?.let { this.createAbility(it, pokemon.form)?.let(pokemon::updateAbility) }
@@ -395,6 +405,9 @@ open class PokemonProperties {
ivs.forEach { stat ->
pokemon.setIV(stat.key, stat.value)
}
ivs.hyperTrainedIVs.forEach { stat ->
pokemon.hyperTrainIV(stat.key, stat.value)
}
}
evs?.let { evs ->
evs.forEach { stat ->
@@ -626,8 +639,8 @@ open class PokemonProperties {
nature?.let { nbt.putString(DataKeys.POKEMON_NATURE, it) }
ability?.let { nbt.putString(DataKeys.POKEMON_ABILITY, it) }
status?.let { nbt.putString(DataKeys.POKEMON_STATUS_NAME, it) }
ivs?.let { nbt.put(DataKeys.POKEMON_IVS, it.saveToNBT(CompoundTag())) }
evs?.let { nbt.put(DataKeys.POKEMON_EVS, it.saveToNBT(CompoundTag())) }
ivs?.let { nbt.put(DataKeys.POKEMON_IVS, IVs.CODEC.encodeStart(NbtOps.INSTANCE, it).result().get()) }
evs?.let { nbt.put(DataKeys.POKEMON_EVS, EVs.CODEC.encodeStart(NbtOps.INSTANCE, it).result().get()) }
type?.let { nbt.putString(DataKeys.ELEMENTAL_TYPE, it) }
teraType?.let { nbt.putString(DataKeys.POKEMON_TERA_TYPE, it) }
dmaxLevel?.let { nbt.putInt(DataKeys.POKEMON_DMAX_LEVEL, it) }
@@ -657,8 +670,8 @@ open class PokemonProperties {
nature = if (tag.contains(DataKeys.POKEMON_NATURE)) tag.getString(DataKeys.POKEMON_NATURE) else null
ability = if (tag.contains(DataKeys.POKEMON_ABILITY)) tag.getString(DataKeys.POKEMON_ABILITY) else null
status = if (tag.contains(DataKeys.POKEMON_STATUS_NAME)) tag.getString(DataKeys.POKEMON_STATUS_NAME) else null
ivs = if (tag.contains(DataKeys.POKEMON_IVS)) IVs().loadFromNBT(tag.getCompound(DataKeys.POKEMON_IVS)) as IVs else null
evs = if (tag.contains(DataKeys.POKEMON_EVS)) EVs().loadFromNBT(tag.getCompound(DataKeys.POKEMON_EVS)) as EVs else null
ivs = if (tag.contains(DataKeys.POKEMON_IVS)) IVs.CODEC.decode(NbtOps.INSTANCE, tag.getCompound(DataKeys.POKEMON_IVS)).result().getOrNull()?.first else null
evs = if (tag.contains(DataKeys.POKEMON_EVS)) EVs.CODEC.decode(NbtOps.INSTANCE, tag.getCompound(DataKeys.POKEMON_EVS)).result().getOrNull()?.first else null
type = if (tag.contains(DataKeys.ELEMENTAL_TYPE)) tag.getString(DataKeys.ELEMENTAL_TYPE) else null
teraType = if (tag.contains(DataKeys.POKEMON_TERA_TYPE)) tag.getString(DataKeys.POKEMON_TERA_TYPE) else null
dmaxLevel = if (tag.contains(DataKeys.POKEMON_DMAX_LEVEL)) tag.getInt(DataKeys.POKEMON_DMAX_LEVEL) else null
@@ -690,8 +703,8 @@ open class PokemonProperties {
nature?.let { json.addProperty(DataKeys.POKEMON_NATURE, it) }
ability?.let { json.addProperty(DataKeys.POKEMON_ABILITY, it) }
status?.let { json.addProperty(DataKeys.POKEMON_STATUS_NAME, it) }
ivs?.let { json.add(DataKeys.POKEMON_IVS, it.saveToJSON(JsonObject())) }
evs?.let { json.add(DataKeys.POKEMON_EVS, it.saveToJSON(JsonObject())) }
ivs?.let { json.add(DataKeys.POKEMON_IVS, IVs.CODEC.encodeStart(JsonOps.INSTANCE, it).result().get()) }
evs?.let { json.add(DataKeys.POKEMON_EVS, EVs.CODEC.encodeStart(JsonOps.INSTANCE, it).result().get()) }
type?.let { json.addProperty(DataKeys.ELEMENTAL_TYPE, it) }
teraType?.let { json.addProperty(DataKeys.POKEMON_TERA_TYPE, it) }
dmaxLevel?.let { json.addProperty(DataKeys.POKEMON_DMAX_LEVEL, it) }
@@ -722,8 +735,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.CODEC.decode(JsonOps.INSTANCE, it).result().getOrNull()?.first }
evs = json.getAsJsonObject(DataKeys.POKEMON_EVS)?.let { EVs.CODEC.decode(JsonOps.INSTANCE, it).result().getOrNull()?.first }
type = json.get(DataKeys.ELEMENTAL_TYPE)?.asString
teraType = json.get(DataKeys.POKEMON_TERA_TYPE)?.asString
dmaxLevel = json.get(DataKeys.POKEMON_DMAX_LEVEL)?.asInt
@@ -798,4 +811,19 @@ open class PokemonProperties {
return potentialAbility.template.create(false, potentialAbility.priority)
}
/**
* Shared logic for figuring out what range of levels is possible for a Pokémon, given that some
* kind of optional level range has been requested. Used mainly as a thing for spawning to avoid
* copy-pasting code.
*/
fun deriveLevelRange(levelRange: IntRange?): IntRange {
return levelRange.let { levelRange ->
val pokemonLevel = level
levelRange
?: pokemonLevel?.until(pokemonLevel)
?: IntRange(1, config.maxPokemonLevel)
}
}
fun hasSpecies() = species?.let { PokemonSpecies.getByIdentifier(it.asIdentifierDefaultingNamespace()) } != null
}
@@ -39,9 +39,9 @@ interface RidingBehaviour<Settings : RidingBehaviourSettings, State : RidingBeha
fun speed(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): Float
fun clampPassengerRotation(settings: Settings, state: State, entity: PokemonEntity, driver: LivingEntity) {}
fun clampPassengerRotation(settings: Settings, state: State, vehicle: PokemonEntity, driver: LivingEntity) {}
fun updatePassengerRotation(settings: Settings, state: State, entity: PokemonEntity, driver: LivingEntity) {}
fun updatePassengerRotation(settings: Settings, state: State, vehicle: PokemonEntity, driver: LivingEntity) {}
fun rotation(settings: Settings, state: State, vehicle: PokemonEntity, driver: LivingEntity): Vec2
@@ -88,6 +88,8 @@ interface RidingBehaviour<Settings : RidingBehaviourSettings, State : RidingBeha
fun shouldRotatePlayerHead(settings: Settings, state: State, vehicle: PokemonEntity): Boolean
fun maxUpStep(settings: Settings, state: State, vehicle: PokemonEntity): Float? = null
fun createDefaultState(settings: Settings): State
}
@@ -23,8 +23,8 @@ import net.minecraft.world.phys.Vec3
* @author landonjw
*/
open class RidingBehaviourState {
open val rideVelocity: SidedRidingState<Vec3> = ridingState(Vec3.ZERO, Side.BOTH)
open val stamina: SidedRidingState<Float> = ridingState(1.0F, Side.BOTH)
open val rideVelocity: SidedRidingState<Vec3> = ridingState(Vec3.ZERO, Side.CLIENT)
open val stamina: SidedRidingState<Float> = ridingState(1.0F, Side.CLIENT)
open fun reset() {
rideVelocity.set(Vec3.ZERO, true)
@@ -8,23 +8,28 @@
package com.cobblemon.mod.common.api.riding.behaviour
import com.cobblemon.mod.common.api.riding.behaviour.types.*
import com.cobblemon.mod.common.api.riding.behaviour.types.air.*
import com.cobblemon.mod.common.api.riding.behaviour.types.composite.CompositeBehaviour
import com.cobblemon.mod.common.api.riding.behaviour.types.land.HorseBehaviour
import com.cobblemon.mod.common.api.riding.behaviour.types.land.VehicleBehaviour
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BoatBehaviour
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BurstBehaviour
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.DolphinBehaviour
import net.minecraft.resources.ResourceLocation
object RidingBehaviours {
val behaviours = mutableMapOf<ResourceLocation, RidingBehaviour<RidingBehaviourSettings, RidingBehaviourState>>()
init {
register(BirdAirBehaviour.KEY, BirdAirBehaviour())
register(BirdBehaviour.KEY, BirdBehaviour())
register(DolphinBehaviour.KEY, DolphinBehaviour())
register(GenericLandBehaviour.KEY, GenericLandBehaviour())
register(GenericSwimBehaviour.KEY, GenericSwimBehaviour())
register(GliderAirBehaviour.KEY, GliderAirBehaviour())
register(HorseBehaviour.KEY, HorseBehaviour())
register(BoatBehaviour.KEY, BoatBehaviour())
register(GliderBehaviour.KEY, GliderBehaviour())
register(HelicopterBehaviour.KEY, HelicopterBehaviour())
register(JetAirBehaviour.KEY, JetAirBehaviour())
register(SwimDashBehaviour.KEY, SwimDashBehaviour())
register(VehicleLandBehaviour.KEY, VehicleLandBehaviour())
register(JetBehaviour.KEY, JetBehaviour())
register(BurstBehaviour.KEY, BurstBehaviour())
register(VehicleBehaviour.KEY, VehicleBehaviour())
register(HoverBehaviour.KEY, HoverBehaviour())
register(CompositeBehaviour.KEY, CompositeBehaviour())
}
@@ -26,7 +26,7 @@ import net.minecraft.world.phys.Vec3
class RidingController<Settings : RidingBehaviourSettings, State : RidingBehaviourState>(val behaviour: RidingBehaviour<Settings, State>) : RidingBehaviour<Settings, State> {
override val key = behaviour.key
override fun getRidingStyle(settings: Settings, state: State): RidingStyle {
return behaviour.getRidingStyle(settings, state)
}
@@ -45,6 +45,16 @@ class RidingController<Settings : RidingBehaviourSettings, State : RidingBehavio
return behaviour.speed(settings, state, vehicle, driver)
}
override fun updatePassengerRotation(
settings: Settings,
state: State,
vehicle: PokemonEntity,
driver: LivingEntity
) {
if (!isActive(settings, state, vehicle)) return
return behaviour.updatePassengerRotation(settings, state, vehicle, driver)
}
override fun clampPassengerRotation(settings: Settings, state: State, vehicle: PokemonEntity, driver: LivingEntity) {
if (!isActive(settings, state, vehicle)) return
return behaviour.clampPassengerRotation(settings, state, vehicle, driver)
@@ -175,6 +185,11 @@ class RidingController<Settings : RidingBehaviourSettings, State : RidingBehavio
return behaviour.setRideBar(settings, state, vehicle, driver)
}
override fun maxUpStep(settings: Settings, state: State, vehicle: PokemonEntity): Float? {
if (!isActive(settings, state, vehicle)) return null
return behaviour.maxUpStep(settings, state, vehicle)
}
override fun createDefaultState(settings: Settings): State {
return behaviour.createDefaultState(settings)
}
@@ -1,267 +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.riding.behaviour.types
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.OrientationControllable
import com.cobblemon.mod.common.api.riding.RidingStyle
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviour
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
import com.cobblemon.mod.common.api.riding.posing.PoseOption
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.*
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.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 net.minecraft.world.phys.shapes.Shapes
class GenericSwimBehaviour : RidingBehaviour<GenericSwimSettings, RidingBehaviourState> {
companion object {
val KEY = cobblemonResource("swim/generic")
}
override val key = KEY
override fun getRidingStyle(settings: GenericSwimSettings, state: RidingBehaviourState): RidingStyle {
return RidingStyle.LIQUID
}
val poseProvider = PoseProvider<GenericSwimSettings, RidingBehaviourState>(PoseType.FLOAT)
.with(PoseOption(PoseType.SWIM) { _, _, entity -> entity.isSwimming && entity.entityData.get(PokemonEntity.MOVING) })
override fun isActive(settings: GenericSwimSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
if (vehicle.isInWater || vehicle.isUnderWater) {
return@any true
}
val blockState = vehicle.level().getBlockState(it)
return@any !blockState.fluidState.isEmpty
}
}
override fun pose(settings: GenericSwimSettings, state: RidingBehaviourState, vehicle: PokemonEntity): PoseType {
return poseProvider.select(settings, state, vehicle)
}
override fun speed(settings: GenericSwimSettings, state: RidingBehaviourState, vehicle: PokemonEntity, driver: Player): Float {
return vehicle.runtime.resolveFloat(settings.speed)
}
override fun rotation(
settings: GenericSwimSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: LivingEntity
): Vec2 {
return Vec2(driver.xRot * 0.5f, driver.yRot)
}
override fun velocity(
settings: GenericSwimSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player,
input: Vec3
): Vec3 {
val runtime = vehicle.runtime
val driveFactor = runtime.resolveFloat(settings.driveFactor)
val strafeFactor = runtime.resolveFloat(settings.strafeFactor)
val f = driver.xxa * strafeFactor
var g = driver.zza * driveFactor
if (g <= 0.0f) {
g *= runtime.resolveFloat(settings.reverseDriveFactor)
}
val velocity = Vec3(f.toDouble(), 0.0, g.toDouble())
return velocity
}
override fun angRollVel(
settings: GenericSwimSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player,
deltaTime: Double
): Vec3 {
return Vec3.ZERO
}
override fun rotationOnMouseXY(
settings: GenericSwimSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player,
mouseY: Double,
mouseX: Double,
mouseYSmoother: SmoothDouble,
mouseXSmoother: SmoothDouble,
sensitivity: Double,
deltaTime: Double
): Vec3 {
if (driver !is OrientationControllable) return Vec3.ZERO
//Might need to add the smoothing here for default.
val invertRoll = if (Cobblemon.config.invertRoll) -1 else 1
val invertPitch = if (Cobblemon.config.invertPitch) -1 else 1
return Vec3(0.0, mouseY * invertPitch, mouseX * invertRoll)
}
override fun canJump(
settings: GenericSwimSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player
): Boolean {
return vehicle.runtime.resolveBoolean(settings.canJump)
}
override fun setRideBar(
settings: GenericSwimSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player
): Float {
return 0.0f
}
override fun jumpForce(
settings: GenericSwimSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player,
jumpStrength: Int
): Vec3 {
val runtime = vehicle.runtime
runtime.environment.query.addFunction("jump_strength") { DoubleValue(jumpStrength.toDouble()) }
val jumpVector = settings.jumpVector.map { runtime.resolveFloat(it) }
return Vec3(jumpVector[0].toDouble(), jumpVector[1].toDouble(), jumpVector[2].toDouble())
}
override fun gravity(
settings: GenericSwimSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
regularGravity: Double
): Double {
return regularGravity
}
override fun rideFovMultiplier(
settings: GenericSwimSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player
): Float {
return 1.0f
}
override fun useAngVelSmoothing(settings: GenericSwimSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
return false
}
override fun useRidingAltPose(
settings: GenericSwimSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player
): ResourceLocation {
return cobblemonResource("no_pose")
}
override fun inertia(settings: GenericSwimSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Double {
return 0.5
}
override fun shouldRoll(settings: GenericSwimSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
return false
}
override fun turnOffOnGround(settings: GenericSwimSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
return false
}
override fun dismountOnShift(settings: GenericSwimSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
return false
}
override fun shouldRotatePokemonHead(
settings: GenericSwimSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun shouldRotatePlayerHead(
settings: GenericSwimSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun createDefaultState(settings: GenericSwimSettings) = RidingBehaviourState()
}
class GenericSwimSettings : RidingBehaviourSettings {
override val key = GenericSwimBehaviour.KEY
var canJump = "true".asExpression()
private set
var jumpVector = listOf("0".asExpression(), "0.3".asExpression(), "0".asExpression())
private set
var speed = "1.0".asExpression()
private set
var driveFactor = "1.0".asExpression()
private set
var reverseDriveFactor = "0.25".asExpression()
private set
var strafeFactor = "0.2".asExpression()
private set
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeResourceLocation(key)
buffer.writeExpression(canJump)
buffer.writeExpression(jumpVector[0])
buffer.writeExpression(jumpVector[1])
buffer.writeExpression(jumpVector[2])
buffer.writeExpression(speed)
buffer.writeExpression(driveFactor)
buffer.writeExpression(reverseDriveFactor)
buffer.writeExpression(strafeFactor)
}
override fun decode(buffer: RegistryFriendlyByteBuf) {
canJump = buffer.readExpression()
jumpVector = listOf(
buffer.readExpression(),
buffer.readExpression(),
buffer.readExpression()
)
speed = buffer.readExpression()
driveFactor = buffer.readExpression()
reverseDriveFactor = buffer.readExpression()
strafeFactor = buffer.readExpression()
}
}
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding.behaviour.types
package com.cobblemon.mod.common.api.riding.behaviour.types.air
import com.bedrockk.molang.Expression
import com.bedrockk.molang.runtime.MoLangMath.lerp
@@ -33,31 +33,31 @@ import net.minecraft.world.phys.Vec3
import org.joml.Vector3f
import kotlin.math.*
class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
companion object {
val KEY = cobblemonResource("air/bird")
}
override val key: ResourceLocation = KEY
override fun getRidingStyle(settings: BirdAirSettings, state: BirdAirState): RidingStyle {
override fun getRidingStyle(settings: BirdSettings, state: BirdState): RidingStyle {
return RidingStyle.AIR
}
val poseProvider = PoseProvider<BirdAirSettings, BirdAirState>(PoseType.HOVER)
val poseProvider = PoseProvider<BirdSettings, BirdState>(PoseType.HOVER)
.with(PoseOption(PoseType.FLY) { _, state, _ -> state.rideVelocity.get().z > 0.2 })
override fun isActive(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity): Boolean {
override fun isActive(settings: BirdSettings, state: BirdState, vehicle: PokemonEntity): Boolean {
return true
}
override fun pose(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity): PoseType {
override fun pose(settings: BirdSettings, state: BirdState, vehicle: PokemonEntity): PoseType {
return poseProvider.select(settings, state, vehicle)
}
override fun speed(
settings: BirdAirSettings,
state: BirdAirState,
settings: BirdSettings,
state: BirdState,
vehicle: PokemonEntity,
driver: Player
): Float {
@@ -65,8 +65,8 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
}
override fun rotation(
settings: BirdAirSettings,
state: BirdAirState,
settings: BirdSettings,
state: BirdState,
vehicle: PokemonEntity,
driver: LivingEntity
): Vec2 {
@@ -74,8 +74,8 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
}
override fun velocity(
settings: BirdAirSettings,
state: BirdAirState,
settings: BirdSettings,
state: BirdState,
vehicle: PokemonEntity,
driver: Player,
input: Vec3
@@ -122,7 +122,7 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
/*
* Calculates the change in the ride space vector due to player input and ride state
*/
fun calculateRideSpaceVel(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity, driver: Player) {
fun calculateRideSpaceVel(settings: BirdSettings, state: BirdState, vehicle: PokemonEntity, driver: Player) {
//retrieve stats
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
val glideTopSpeed = vehicle.runtime.resolveDouble(settings.glidespeedExpr)
@@ -240,8 +240,8 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
}
override fun angRollVel(
settings: BirdAirSettings,
state: BirdAirState,
settings: BirdSettings,
state: BirdState,
vehicle: PokemonEntity,
driver: Player,
deltaTime: Double
@@ -282,8 +282,8 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
}
override fun rotationOnMouseXY(
settings: BirdAirSettings,
state: BirdAirState,
settings: BirdSettings,
state: BirdState,
vehicle: PokemonEntity,
driver: Player,
mouseY: Double,
@@ -367,8 +367,8 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
}
override fun canJump(
settings: BirdAirSettings,
state: BirdAirState,
settings: BirdSettings,
state: BirdState,
vehicle: PokemonEntity,
driver: Player
): Boolean {
@@ -376,8 +376,8 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
}
override fun setRideBar(
settings: BirdAirSettings,
state: BirdAirState,
settings: BirdSettings,
state: BirdState,
vehicle: PokemonEntity,
driver: Player
): Float {
@@ -385,8 +385,8 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
}
override fun jumpForce(
settings: BirdAirSettings,
state: BirdAirState,
settings: BirdSettings,
state: BirdState,
vehicle: PokemonEntity,
driver: Player,
jumpStrength: Int
@@ -395,8 +395,8 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
}
override fun gravity(
settings: BirdAirSettings,
state: BirdAirState,
settings: BirdSettings,
state: BirdState,
vehicle: PokemonEntity,
regularGravity: Double
): Double {
@@ -404,8 +404,8 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
}
override fun rideFovMultiplier(
settings: BirdAirSettings,
state: BirdAirState,
settings: BirdSettings,
state: BirdState,
vehicle: PokemonEntity,
driver: Player
): Float {
@@ -420,16 +420,16 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
}
override fun useAngVelSmoothing(
settings: BirdAirSettings,
state: BirdAirState,
settings: BirdSettings,
state: BirdState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun useRidingAltPose(
settings: BirdAirSettings,
state: BirdAirState,
settings: BirdSettings,
state: BirdState,
vehicle: PokemonEntity,
driver: Player
): ResourceLocation {
@@ -439,44 +439,44 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
return cobblemonResource("no_pose")
}
override fun inertia(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity): Double {
override fun inertia(settings: BirdSettings, state: BirdState, vehicle: PokemonEntity): Double {
return 0.5
}
override fun shouldRoll(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity): Boolean {
override fun shouldRoll(settings: BirdSettings, state: BirdState, vehicle: PokemonEntity): Boolean {
return true
}
override fun turnOffOnGround(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity): Boolean {
override fun turnOffOnGround(settings: BirdSettings, state: BirdState, vehicle: PokemonEntity): Boolean {
return false
}
override fun dismountOnShift(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity): Boolean {
override fun dismountOnShift(settings: BirdSettings, state: BirdState, vehicle: PokemonEntity): Boolean {
return false
}
override fun shouldRotatePokemonHead(
settings: BirdAirSettings,
state: BirdAirState,
settings: BirdSettings,
state: BirdState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun shouldRotatePlayerHead(
settings: BirdAirSettings,
state: BirdAirState,
settings: BirdSettings,
state: BirdState,
vehicle: PokemonEntity
): Boolean {
return true
}
override fun createDefaultState(settings: BirdAirSettings) = BirdAirState()
override fun createDefaultState(settings: BirdSettings) = BirdState()
}
class BirdAirSettings : RidingBehaviourSettings {
override val key = BirdAirBehaviour.KEY
class BirdSettings : RidingBehaviourSettings {
override val key = BirdBehaviour.KEY
var infiniteAltitude: Expression = "false".asExpression()
private set
@@ -518,7 +518,7 @@ class BirdAirSettings : RidingBehaviourSettings {
}
}
class BirdAirState : RidingBehaviourState() {
class BirdState : RidingBehaviourState() {
var gliding = ridingState(false, Side.CLIENT)
var lastGlide = ridingState(-100L, Side.CLIENT)
var currRollCorrectionForce = ridingState(0.0, Side.CLIENT)
@@ -542,10 +542,10 @@ class BirdAirState : RidingBehaviourState() {
}
override fun toString(): String {
return "BirdAirState(rideVelocity=${rideVelocity.get()}, stamina=${stamina.get()}, gliding=${gliding.get()})"
return "BirdState(rideVelocity=${rideVelocity.get()}, stamina=${stamina.get()}, gliding=${gliding.get()})"
}
override fun copy() = BirdAirState().also {
override fun copy() = BirdState().also {
it.rideVelocity.set(this.rideVelocity.get(), forced = true)
it.stamina.set(this.stamina.get(), forced = true)
it.gliding.set(this.gliding.get(), forced = true)
@@ -554,7 +554,7 @@ class BirdAirState : RidingBehaviourState() {
}
override fun shouldSync(previous: RidingBehaviourState): Boolean {
if (previous !is BirdAirState) return false
if (previous !is BirdState) return false
if (previous.gliding.get() != gliding.get()) return true
return super.shouldSync(previous)
}
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding.behaviour.types
package com.cobblemon.mod.common.api.riding.behaviour.types.air
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.Cobblemon
@@ -29,34 +29,34 @@ import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourState> {
class GliderBehaviour : RidingBehaviour<GliderSettings, RidingBehaviourState> {
companion object {
val KEY = cobblemonResource("air/glider")
}
override val key = KEY
override fun getRidingStyle(settings: GliderAirSettings, state: RidingBehaviourState): RidingStyle {
override fun getRidingStyle(settings: GliderSettings, state: RidingBehaviourState): RidingStyle {
return RidingStyle.AIR
}
val poseProvider = PoseProvider<GliderAirSettings, RidingBehaviourState>(PoseType.HOVER)
val poseProvider = PoseProvider<GliderSettings, RidingBehaviourState>(PoseType.HOVER)
.with(PoseOption(PoseType.FLY) { _, _, entity -> entity.entityData.get(PokemonEntity.MOVING) })
override fun isActive(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
override fun isActive(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
return true
}
override fun pose(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity): PoseType {
override fun pose(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity): PoseType {
return poseProvider.select(settings, state, vehicle)
}
override fun speed(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity, driver: Player): Float {
override fun speed(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity, driver: Player): Float {
return vehicle.runtime.resolveFloat(settings.speed)
}
override fun rotation(
settings: GliderAirSettings,
settings: GliderSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: LivingEntity
@@ -65,7 +65,7 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
}
override fun velocity(
settings: GliderAirSettings,
settings: GliderSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player,
@@ -80,7 +80,7 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
}
override fun angRollVel(
settings: GliderAirSettings,
settings: GliderSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player,
@@ -90,7 +90,7 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
}
override fun rotationOnMouseXY(
settings: GliderAirSettings,
settings: GliderSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player,
@@ -109,12 +109,12 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
return Vec3(0.0, mouseY * invertPitch, mouseX * invertRoll)
}
override fun canJump(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity, driver: Player): Boolean {
override fun canJump(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity, driver: Player): Boolean {
return false
}
override fun setRideBar(
settings: GliderAirSettings,
settings: GliderSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player
@@ -123,7 +123,7 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
}
override fun jumpForce(
settings: GliderAirSettings,
settings: GliderSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player,
@@ -133,7 +133,7 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
}
override fun gravity(
settings: GliderAirSettings,
settings: GliderSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
regularGravity: Double
@@ -142,7 +142,7 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
}
override fun rideFovMultiplier(
settings: GliderAirSettings,
settings: GliderSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player
@@ -150,12 +150,12 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
return 1.0f
}
override fun useAngVelSmoothing(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
override fun useAngVelSmoothing(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
return false
}
override fun useRidingAltPose(
settings: GliderAirSettings,
settings: GliderSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player
@@ -163,35 +163,35 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
return cobblemonResource("no_pose")
}
override fun inertia(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Double {
override fun inertia(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Double {
return 0.5
}
override fun shouldRoll(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
override fun shouldRoll(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
return false
}
override fun turnOffOnGround(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
override fun turnOffOnGround(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
return false
}
override fun dismountOnShift(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
override fun dismountOnShift(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
return false
}
override fun shouldRotatePokemonHead(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
override fun shouldRotatePokemonHead(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
return false
}
override fun shouldRotatePlayerHead(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
override fun shouldRotatePlayerHead(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
return false
}
override fun createDefaultState(settings: GliderAirSettings) = RidingBehaviourState()
override fun createDefaultState(settings: GliderSettings) = RidingBehaviourState()
}
class GliderAirSettings : RidingBehaviourSettings {
override val key = GliderAirBehaviour.KEY
class GliderSettings : RidingBehaviourSettings {
override val key = GliderBehaviour.KEY
var glideSpeed: Expression = "0.1".asExpression()
private set
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding.behaviour.types
package com.cobblemon.mod.common.api.riding.behaviour.types.air
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.Cobblemon
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding.behaviour.types
package com.cobblemon.mod.common.api.riding.behaviour.types.air
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.api.riding.RidingStyle
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding.behaviour.types
package com.cobblemon.mod.common.api.riding.behaviour.types.air
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.Cobblemon
@@ -30,21 +30,21 @@ import net.minecraft.world.phys.Vec3
import net.minecraft.world.phys.shapes.Shapes
import kotlin.math.*
class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
companion object {
val KEY = cobblemonResource("air/jet")
}
override val key = KEY
override fun getRidingStyle(settings: JetAirSettings, state: JetAirState): RidingStyle {
override fun getRidingStyle(settings: JetSettings, state: JetState): RidingStyle {
return RidingStyle.AIR
}
val poseProvider = PoseProvider<JetAirSettings, JetAirState>(PoseType.HOVER)
val poseProvider = PoseProvider<JetSettings, JetState>(PoseType.HOVER)
.with(PoseOption(PoseType.FLY) { _, state, _ -> state.rideVelocity.get().z > 0.1 })
override fun isActive(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Boolean {
override fun isActive(settings: JetSettings, state: JetState, vehicle: PokemonEntity): Boolean {
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
//Need to check other fluids
if (vehicle.isInWater || vehicle.isUnderWater) {
@@ -59,11 +59,11 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
}
}
override fun pose(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): PoseType {
override fun pose(settings: JetSettings, state: JetState, vehicle: PokemonEntity): PoseType {
return poseProvider.select(settings, state, vehicle)
}
override fun speed(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity, driver: Player): Float {
override fun speed(settings: JetSettings, state: JetState, vehicle: PokemonEntity, driver: Player): Float {
//retrieve stats
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
val staminaStat = vehicle.runtime.resolveDouble(settings.staminaExpr)
@@ -104,8 +104,8 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
}
override fun rotation(
settings: JetAirSettings,
state: JetAirState,
settings: JetSettings,
state: JetState,
vehicle: PokemonEntity,
driver: LivingEntity
): Vec2 {
@@ -113,8 +113,8 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
}
override fun velocity(
settings: JetAirSettings,
state: JetAirState,
settings: JetSettings,
state: JetState,
vehicle: PokemonEntity,
driver: Player,
input: Vec3
@@ -153,8 +153,8 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
* Calculates the change in the ride space vector due to player input and ride state
*/
private fun calculateRideSpaceVel(
settings: JetAirSettings,
state: JetAirState,
settings: JetSettings,
state: JetState,
vehicle: PokemonEntity,
driver: Player
) {
@@ -186,8 +186,8 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
}
override fun angRollVel(
settings: JetAirSettings,
state: JetAirState,
settings: JetSettings,
state: JetState,
vehicle: PokemonEntity,
driver: Player,
deltaTime: Double
@@ -211,8 +211,8 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
}
override fun rotationOnMouseXY(
settings: JetAirSettings,
state: JetAirState,
settings: JetSettings,
state: JetState,
vehicle: PokemonEntity,
driver: Player,
mouseY: Double,
@@ -273,8 +273,8 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
}
override fun canJump(
settings: JetAirSettings,
state: JetAirState,
settings: JetSettings,
state: JetState,
vehicle: PokemonEntity,
driver: Player
): Boolean {
@@ -282,8 +282,8 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
}
override fun setRideBar(
settings: JetAirSettings,
state: JetAirState,
settings: JetSettings,
state: JetState,
vehicle: PokemonEntity,
driver: Player
): Float {
@@ -291,8 +291,8 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
}
override fun jumpForce(
settings: JetAirSettings,
state: JetAirState,
settings: JetSettings,
state: JetState,
vehicle: PokemonEntity,
driver: Player,
jumpStrength: Int
@@ -301,8 +301,8 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
}
override fun gravity(
settings: JetAirSettings,
state: JetAirState,
settings: JetSettings,
state: JetState,
vehicle: PokemonEntity,
regularGravity: Double
): Double {
@@ -310,8 +310,8 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
}
override fun rideFovMultiplier(
settings: JetAirSettings,
state: JetAirState,
settings: JetSettings,
state: JetState,
vehicle: PokemonEntity,
driver: Player
): Float {
@@ -326,52 +326,52 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
return 1.0f + normalizedSpeed.pow(2).toFloat() * 0.2f
}
override fun useAngVelSmoothing(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Boolean {
override fun useAngVelSmoothing(settings: JetSettings, state: JetState, vehicle: PokemonEntity): Boolean {
return true
}
override fun useRidingAltPose(
settings: JetAirSettings,
state: JetAirState,
settings: JetSettings,
state: JetState,
vehicle: PokemonEntity,
driver: Player
): ResourceLocation {
return cobblemonResource("no_pose")
}
override fun inertia(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Double {
override fun inertia(settings: JetSettings, state: JetState, vehicle: PokemonEntity): Double {
return 1.0
}
override fun shouldRoll(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Boolean {
override fun shouldRoll(settings: JetSettings, state: JetState, vehicle: PokemonEntity): Boolean {
return true
}
override fun turnOffOnGround(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Boolean {
override fun turnOffOnGround(settings: JetSettings, state: JetState, vehicle: PokemonEntity): Boolean {
return false
}
override fun dismountOnShift(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Boolean {
override fun dismountOnShift(settings: JetSettings, state: JetState, vehicle: PokemonEntity): Boolean {
return false
}
override fun shouldRotatePokemonHead(
settings: JetAirSettings,
state: JetAirState,
settings: JetSettings,
state: JetState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun shouldRotatePlayerHead(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Boolean {
override fun shouldRotatePlayerHead(settings: JetSettings, state: JetState, vehicle: PokemonEntity): Boolean {
return false
}
override fun createDefaultState(settings: JetAirSettings) = JetAirState()
override fun createDefaultState(settings: JetSettings) = JetState()
}
class JetAirSettings : RidingBehaviourSettings {
override val key = JetAirBehaviour.KEY
class JetSettings : RidingBehaviourSettings {
override val key = JetBehaviour.KEY
var gravity: Expression = "0".asExpression()
private set
@@ -428,7 +428,7 @@ class JetAirSettings : RidingBehaviourSettings {
}
}
class JetAirState : RidingBehaviourState() {
class JetState : RidingBehaviourState() {
var currSpeed = ridingState(0.0, Side.CLIENT)
var currMouseXForce = ridingState(0.0, Side.CLIENT)
var currMouseYForce = ridingState(0.0, Side.CLIENT)
@@ -451,7 +451,7 @@ class JetAirState : RidingBehaviourState() {
currMouseYForce.set(0.0, forced = true)
}
override fun copy() = JetAirState().also {
override fun copy() = JetState().also {
it.currSpeed.set(currSpeed.get(), forced = true)
it.stamina.set(stamina.get(), forced = true)
it.rideVelocity.set(rideVelocity.get(), forced = true)
@@ -460,7 +460,7 @@ class JetAirState : RidingBehaviourState() {
}
override fun shouldSync(previous: RidingBehaviourState): Boolean {
if (previous !is JetAirState) return false
if (previous !is JetState) return false
if (previous.currSpeed != currSpeed) return true
return super.shouldSync(previous)
}
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding.behaviour.types
package com.cobblemon.mod.common.api.riding.behaviour.types.land
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.api.riding.RidingStyle
@@ -30,25 +30,25 @@ import net.minecraft.world.phys.Vec3
import net.minecraft.world.phys.shapes.Shapes
import kotlin.math.*
class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandState> {
class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
companion object {
val KEY = cobblemonResource("land/generic")
val KEY = cobblemonResource("land/horse")
}
override val key = KEY
override fun getRidingStyle(settings: GenericLandSettings, state: GenericLandState): RidingStyle {
override fun getRidingStyle(settings: HorseSettings, state: HorseState): RidingStyle {
return RidingStyle.LAND
}
val poseProvider = PoseProvider<GenericLandSettings, GenericLandState>(PoseType.STAND)
val poseProvider = PoseProvider<HorseSettings, HorseState>(PoseType.STAND)
.with(PoseOption(PoseType.WALK) { _, state, _ ->
return@PoseOption abs(state.rideVelocity.get().z) > 0.0
})
override fun isActive(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity
): Boolean {
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
@@ -66,16 +66,16 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
}
override fun pose(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity
): PoseType {
return this.poseProvider.select(settings, state, vehicle)
}
override fun speed(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity,
driver: Player
): Float {
@@ -102,8 +102,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
}
override fun updatePassengerRotation(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity,
driver: LivingEntity
) {
@@ -128,8 +128,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
}
override fun clampPassengerRotation(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity,
driver: LivingEntity
) {
@@ -143,8 +143,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
override fun rotation(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity,
driver: LivingEntity
): Vec2 {
@@ -161,8 +161,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
* without it being instant.
*/
fun calcRotAmount(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity,
driver: LivingEntity
): Float {
@@ -198,8 +198,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
override fun velocity(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity,
driver: Player,
input: Vec3
@@ -209,8 +209,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
}
private fun calculateRideSpaceVel(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity,
driver: Player
): Vec3 {
@@ -293,8 +293,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
}
override fun angRollVel(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity,
driver: Player,
deltaTime: Double
@@ -303,8 +303,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
}
override fun rotationOnMouseXY(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity,
driver: Player,
mouseY: Double,
@@ -324,8 +324,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
}
override fun canJump(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity,
driver: Player
): Boolean {
@@ -333,8 +333,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
}
override fun setRideBar(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity,
driver: Player
): Float {
@@ -343,8 +343,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
}
override fun jumpForce(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity,
driver: Player,
jumpStrength: Int
@@ -353,8 +353,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
}
override fun gravity(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity,
regularGravity: Double
): Double {
@@ -362,8 +362,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
}
override fun rideFovMultiplier(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity,
driver: Player
): Float {
@@ -371,16 +371,16 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
}
override fun useAngVelSmoothing(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun useRidingAltPose(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity,
driver: Player
): ResourceLocation {
@@ -392,58 +392,58 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
}
override fun inertia(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity
): Double {
return 1.0
}
override fun shouldRoll(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun turnOffOnGround(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun dismountOnShift(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun shouldRotatePokemonHead(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun shouldRotatePlayerHead(
settings: GenericLandSettings,
state: GenericLandState,
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity
): Boolean {
return true
}
override fun createDefaultState(settings: GenericLandSettings) = GenericLandState()
override fun createDefaultState(settings: HorseSettings) = HorseState()
}
class GenericLandSettings : RidingBehaviourSettings {
override val key = GenericLandBehaviour.KEY
class HorseSettings : RidingBehaviourSettings {
override val key = HorseBehaviour.KEY
var canJump = "true".asExpression()
private set
@@ -486,7 +486,7 @@ class GenericLandSettings : RidingBehaviourSettings {
}
class GenericLandState : RidingBehaviourState() {
class HorseState : RidingBehaviourState() {
var sprinting = ridingState(false, Side.CLIENT)
var inAir = ridingState(false, Side.CLIENT)
@@ -508,7 +508,7 @@ class GenericLandState : RidingBehaviourState() {
inAir.set(false, forced = true)
}
override fun copy() = GenericLandState().also {
override fun copy() = HorseState().also {
it.rideVelocity.set(this.rideVelocity.get(), forced = true)
it.stamina.set(this.stamina.get(), forced = true)
it.sprinting.set(this.sprinting.get(), forced = true)
@@ -516,7 +516,7 @@ class GenericLandState : RidingBehaviourState() {
}
override fun shouldSync(previous: RidingBehaviourState): Boolean {
if (previous !is GenericLandState) return false
if (previous !is HorseState) return false
if (previous.sprinting.get() != sprinting.get()) return true
if (previous.inAir.get() != inAir.get()) return true
return super.shouldSync(previous)
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding.behaviour.types
package com.cobblemon.mod.common.api.riding.behaviour.types.land
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.Cobblemon
@@ -31,7 +31,7 @@ import kotlin.math.absoluteValue
import kotlin.math.max
import kotlin.math.min
class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandState> {
class VehicleBehaviour : RidingBehaviour<VehicleSettings, VehicleState> {
companion object {
val KEY = cobblemonResource("land/vehicle")
@@ -54,14 +54,14 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
override val key = KEY
override fun getRidingStyle(settings: VehicleLandSettings, state: VehicleLandState): RidingStyle {
override fun getRidingStyle(settings: VehicleSettings, state: VehicleState): RidingStyle {
return RidingStyle.LAND
}
val poseProvider = PoseProvider<VehicleLandSettings, VehicleLandState>(PoseType.STAND)
val poseProvider = PoseProvider<VehicleSettings, VehicleState>(PoseType.STAND)
.with(PoseOption(PoseType.WALK) { _, _, entity -> entity.entityData.get(PokemonEntity.MOVING) })
override fun isActive(settings: VehicleLandSettings, state: VehicleLandState, vehicle: PokemonEntity): Boolean {
override fun isActive(settings: VehicleSettings, state: VehicleState, vehicle: PokemonEntity): Boolean {
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
//Need to check other fluids
if (vehicle.isInWater || vehicle.isUnderWater) {
@@ -76,13 +76,13 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
}
}
override fun pose(settings: VehicleLandSettings, state: VehicleLandState, vehicle: PokemonEntity): PoseType {
override fun pose(settings: VehicleSettings, state: VehicleState, vehicle: PokemonEntity): PoseType {
return poseProvider.select(settings, state, vehicle)
}
override fun speed(
settings: VehicleLandSettings,
state: VehicleLandState,
settings: VehicleSettings,
state: VehicleState,
vehicle: PokemonEntity,
driver: Player
): Float {
@@ -101,8 +101,8 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
}
override fun rotation(
settings: VehicleLandSettings,
state: VehicleLandState,
settings: VehicleSettings,
state: VehicleState,
vehicle: PokemonEntity,
driver: LivingEntity
): Vec2 {
@@ -113,8 +113,8 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
}
override fun velocity(
settings: VehicleLandSettings,
state: VehicleLandState,
settings: VehicleSettings,
state: VehicleState,
vehicle: PokemonEntity,
driver: Player,
input: Vec3
@@ -134,8 +134,8 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
}
override fun angRollVel(
settings: VehicleLandSettings,
state: VehicleLandState,
settings: VehicleSettings,
state: VehicleState,
vehicle: PokemonEntity,
driver: Player,
deltaTime: Double
@@ -144,8 +144,8 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
}
override fun rotationOnMouseXY(
settings: VehicleLandSettings,
state: VehicleLandState,
settings: VehicleSettings,
state: VehicleState,
vehicle: PokemonEntity,
driver: Player,
mouseY: Double,
@@ -164,8 +164,8 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
}
override fun canJump(
settings: VehicleLandSettings,
state: VehicleLandState,
settings: VehicleSettings,
state: VehicleState,
vehicle: PokemonEntity,
driver: Player
): Boolean {
@@ -173,8 +173,8 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
}
override fun setRideBar(
settings: VehicleLandSettings,
state: VehicleLandState,
settings: VehicleSettings,
state: VehicleState,
vehicle: PokemonEntity,
driver: Player
): Float {
@@ -182,8 +182,8 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
}
override fun jumpForce(
settings: VehicleLandSettings,
state: VehicleLandState,
settings: VehicleSettings,
state: VehicleState,
vehicle: PokemonEntity,
driver: Player,
jumpStrength: Int
@@ -195,8 +195,8 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
}
override fun gravity(
settings: VehicleLandSettings,
state: VehicleLandState,
settings: VehicleSettings,
state: VehicleState,
vehicle: PokemonEntity,
regularGravity: Double
): Double {
@@ -204,8 +204,8 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
}
override fun rideFovMultiplier(
settings: VehicleLandSettings,
state: VehicleLandState,
settings: VehicleSettings,
state: VehicleState,
vehicle: PokemonEntity,
driver: Player
): Float {
@@ -213,67 +213,67 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
}
override fun useAngVelSmoothing(
settings: VehicleLandSettings,
state: VehicleLandState,
settings: VehicleSettings,
state: VehicleState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun useRidingAltPose(
settings: VehicleLandSettings,
state: VehicleLandState,
settings: VehicleSettings,
state: VehicleState,
vehicle: PokemonEntity,
driver: Player
): ResourceLocation {
return cobblemonResource("no_pose")
}
override fun inertia(settings: VehicleLandSettings, state: VehicleLandState, vehicle: PokemonEntity): Double {
override fun inertia(settings: VehicleSettings, state: VehicleState, vehicle: PokemonEntity): Double {
return 0.5
}
override fun shouldRoll(settings: VehicleLandSettings, state: VehicleLandState, vehicle: PokemonEntity): Boolean {
override fun shouldRoll(settings: VehicleSettings, state: VehicleState, vehicle: PokemonEntity): Boolean {
return false
}
override fun turnOffOnGround(
settings: VehicleLandSettings,
state: VehicleLandState,
settings: VehicleSettings,
state: VehicleState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun dismountOnShift(
settings: VehicleLandSettings,
state: VehicleLandState,
settings: VehicleSettings,
state: VehicleState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun shouldRotatePokemonHead(
settings: VehicleLandSettings,
state: VehicleLandState,
settings: VehicleSettings,
state: VehicleState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun shouldRotatePlayerHead(
settings: VehicleLandSettings,
state: VehicleLandState,
settings: VehicleSettings,
state: VehicleState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun createDefaultState(settings: VehicleLandSettings) = VehicleLandState()
override fun createDefaultState(settings: VehicleSettings) = VehicleState()
}
class VehicleLandSettings : RidingBehaviourSettings {
override val key = VehicleLandBehaviour.KEY
class VehicleSettings : RidingBehaviourSettings {
override val key = VehicleBehaviour.KEY
var canJump = "true".asExpression()
private set
@@ -329,7 +329,7 @@ class VehicleLandSettings : RidingBehaviourSettings {
}
}
class VehicleLandState : RidingBehaviourState() {
class VehicleState : RidingBehaviourState() {
var currSpeed = ridingState(0.0, Side.BOTH)
var deltaRotation = ridingState(Vec2.ZERO, Side.BOTH)
@@ -340,10 +340,10 @@ class VehicleLandState : RidingBehaviourState() {
}
override fun toString(): String {
return "VehicleLandState(currSpeed=${currSpeed.get()}, deltaRotation=${deltaRotation.get()})"
return "VehicleState(currSpeed=${currSpeed.get()}, deltaRotation=${deltaRotation.get()})"
}
override fun copy() = VehicleLandState().also {
override fun copy() = VehicleState().also {
it.rideVelocity.set(rideVelocity.get(), forced = true)
it.stamina.set(stamina.get(), forced = true)
it.currSpeed.set(currSpeed.get(), forced = true)
@@ -0,0 +1,383 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding.behaviour.types.liquid
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.OrientationControllable
import com.cobblemon.mod.common.api.riding.RidingStyle
import com.cobblemon.mod.common.api.riding.behaviour.*
import com.cobblemon.mod.common.api.riding.posing.PoseOption
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
import com.cobblemon.mod.common.api.riding.stats.RidingStat
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.*
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.util.Mth
import net.minecraft.util.SmoothDouble
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
import net.minecraft.world.phys.shapes.Shapes
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
class BoatBehaviour : RidingBehaviour<BoatSettings, BoatState> {
companion object {
val KEY = cobblemonResource("liquid/boat")
val TOP_SPEED = 2.0
}
override val key = KEY
override fun getRidingStyle(settings: BoatSettings, state: BoatState): RidingStyle {
return RidingStyle.LIQUID
}
val poseProvider = PoseProvider<BoatSettings, BoatState>(PoseType.FLOAT)
.with(PoseOption(PoseType.SWIM) { _, _, entity -> entity.isSwimming && entity.entityData.get(PokemonEntity.MOVING) })
override fun isActive(settings: BoatSettings, state: BoatState, vehicle: PokemonEntity): Boolean {
if (state.jumpBuffer.get() != -1) {
return true
}
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
if (vehicle.isInWater || vehicle.isUnderWater) {
return@any true
}
val blockState = vehicle.level().getBlockState(it)
return@any !blockState.fluidState.isEmpty
}
}
override fun tick(
settings: BoatSettings,
state: BoatState,
vehicle: PokemonEntity,
driver: Player,
input: Vec3
) {
if (state.jumpBuffer.get() > 5) {
if ((vehicle.isInWater || vehicle.isUnderWater || vehicle.onGround())) {
state.jumpBuffer.set(-1)
}
}
else if (state.jumpBuffer.get() > -1) {
state.jumpBuffer.set(state.jumpBuffer.get() + 1)
}
if (driver.zza == 0f && (vehicle.isInWater || vehicle.isUnderWater)) {
if (state.staminaBuffer.get() >= 20) {
val staminaIncrease = vehicle.getRideStat(RidingStat.STAMINA, RidingStyle.LIQUID, 1.0, 2.0)
state.stamina.set(min(1.0f, state.stamina.get() + 0.01f * staminaIncrease.toFloat()))
}
}
else if (abs(state.rideVelocity.get().z) > 0.1) {
consumeStamina(vehicle, state, 0.01f)
}
state.staminaBuffer.set(state.staminaBuffer.get() + 1)
super.tick(settings, state, vehicle, driver, input)
}
override fun pose(settings: BoatSettings, state: BoatState, vehicle: PokemonEntity): PoseType {
return poseProvider.select(settings, state, vehicle)
}
override fun speed(settings: BoatSettings, state: BoatState, vehicle: PokemonEntity, driver: Player): Float {
return state.rideVelocity.get().length().toFloat()
}
override fun rotation(
settings: BoatSettings,
state: BoatState,
vehicle: PokemonEntity,
driver: LivingEntity
): Vec2 {
state.deltaRotation.set(state.deltaRotation.get() * 0.8)
return Vec2(vehicle.xRot, vehicle.yRot + state.deltaRotation.get().toFloat())
}
override fun velocity(
settings: BoatSettings,
state: BoatState,
vehicle: PokemonEntity,
driver: Player,
input: Vec3
): Vec3 {
applyStrafeRotation(vehicle, driver, state)
var velocity = state.rideVelocity.get()
velocity = applyVelocityFromInput(velocity, vehicle, driver, state)
velocity = applyGravity(velocity, vehicle, settings, state)
velocity = applyJump(velocity, vehicle, driver, state)
state.rideVelocity.set(velocity)
return state.rideVelocity.get()
}
private fun applyVelocityFromInput(velocity: Vec3, vehicle: PokemonEntity, driver: Player, state: BoatState): Vec3 {
val speed = vehicle.getRideStat(RidingStat.SPEED, RidingStyle.LIQUID, 0.8, TOP_SPEED)
val acceleration = vehicle.getRideStat(RidingStat.ACCELERATION, RidingStyle.LIQUID, 0.05, 0.5)
if (state.jumpBuffer.get() != -1 || !(vehicle.isInWater || vehicle.isUnderWater)) {
return velocity
}
val forwardInput = driver.zza.toDouble()
val delta = when {
!hasStamina(state) || forwardInput == 0.0 -> -velocity.z * 0.04
forwardInput < 0.0 -> when {
velocity.z < 0.0 -> forwardInput * acceleration * 0.5
else -> min(forwardInput * acceleration * 0.5, -velocity.z * 0.04) // We never want it to be slower to reverse than no input
}
else -> forwardInput * acceleration
}
return Vec3(
velocity.x,
velocity.y,
Mth.clamp(velocity.z + delta, -speed * 0.25, speed)
)
}
private fun applyJump(velocity: Vec3, vehicle: PokemonEntity, driver: Player, state: BoatState): Vec3 {
if (!driver.jumping) return velocity // Not jumping
if (state.jumpBuffer.get() != -1) return velocity // Already jumped very recently
if (!hasStamina(state)) return velocity // Has no stamina
val jumpStrength = vehicle.getRideStat(RidingStat.JUMP, RidingStyle.LIQUID, 1.0, 2.5)
state.jumpBuffer.set(0)
consumeStamina(vehicle, state, 0.05f)
return Vec3(velocity.x, velocity.y + jumpStrength, velocity.z)
}
private fun applyGravity(velocity: Vec3, vehicle: PokemonEntity, settings: BoatSettings, state: BoatState): Vec3 {
if (state.jumpBuffer.get() == -1 && vehicle.isInWater || vehicle.isUnderWater) {
return Vec3(velocity.x, -0.05, velocity.z)
}
val terminalVelocity = vehicle.runtime.resolveDouble(settings.terminalVelocity)
val gravity = (9.8 / ( 20.0)) * 0.2
return Vec3(velocity.x, max(velocity.y - gravity, terminalVelocity), velocity.z)
}
private fun applyStrafeRotation(vehicle: PokemonEntity, driver: Player, state: BoatState) {
val skill = vehicle.getRideStat(RidingStat.SKILL, RidingStyle.LIQUID, 0.5, 1.5)
val strafe = driver.xxa
if (abs(strafe) > 0) {
val increase = if (strafe > 0) -1 else 1
state.deltaRotation.set(state.deltaRotation.get() + increase * skill)
}
}
private fun hasStamina(state: BoatState): Boolean {
return state.stamina.get() != 0f
}
private fun consumeStamina(vehicle: PokemonEntity, state: BoatState, drain: Float) {
val stamina = vehicle.getRideStat(RidingStat.STAMINA, RidingStyle.LIQUID, 1.0, 5.0)
state.stamina.set(max(0f, state.stamina.get() - drain / stamina.toFloat()))
state.staminaBuffer.set(0)
}
override fun updatePassengerRotation(
settings: BoatSettings,
state: BoatState,
vehicle: PokemonEntity,
driver: LivingEntity
) {
driver.yRot += state.deltaRotation.get().toFloat() * 0.887f
driver.yHeadRot += state.deltaRotation.get().toFloat() * 0.887f
clampPassengerRotation(settings, state, vehicle, driver)
}
override fun clampPassengerRotation(
settings: BoatSettings,
state: BoatState,
vehicle: PokemonEntity,
driver: LivingEntity
) {
driver.setYBodyRot(vehicle.yRot)
val f: Float = Mth.wrapDegrees(driver.yRot - vehicle.yRot)
val g = Mth.clamp(f, -105.0f, 105.0f)
driver.yRotO += g - f
driver.yRot = driver.yRot + g - f
driver.setYHeadRot(driver.yRot)
vehicle.setYHeadRot(driver.yRot)
}
override fun angRollVel(
settings: BoatSettings,
state: BoatState,
vehicle: PokemonEntity,
driver: Player,
deltaTime: Double
): Vec3 {
return Vec3.ZERO
}
override fun rotationOnMouseXY(
settings: BoatSettings,
state: BoatState,
vehicle: PokemonEntity,
driver: Player,
mouseY: Double,
mouseX: Double,
mouseYSmoother: SmoothDouble,
mouseXSmoother: SmoothDouble,
sensitivity: Double,
deltaTime: Double
): Vec3 {
if (driver !is OrientationControllable) return Vec3.ZERO
//Might need to add the smoothing here for default.
val invertRoll = if (Cobblemon.config.invertRoll) -1 else 1
val invertPitch = if (Cobblemon.config.invertPitch) -1 else 1
return Vec3(0.0, mouseY * invertPitch, mouseX * invertRoll)
}
override fun canJump(
settings: BoatSettings,
state: BoatState,
vehicle: PokemonEntity,
driver: Player
): Boolean {
return false
}
override fun setRideBar(
settings: BoatSettings,
state: BoatState,
vehicle: PokemonEntity,
driver: Player
): Float {
return (state.stamina.get() / 1.0f)
}
override fun jumpForce(
settings: BoatSettings,
state: BoatState,
vehicle: PokemonEntity,
driver: Player,
jumpStrength: Int
): Vec3 {
return Vec3.ZERO
}
override fun gravity(
settings: BoatSettings,
state: BoatState,
vehicle: PokemonEntity,
regularGravity: Double
): Double {
return 0.0
}
override fun rideFovMultiplier(
settings: BoatSettings,
state: BoatState,
vehicle: PokemonEntity,
driver: Player
): Float {
if (state.rideVelocity.get().z > TOP_SPEED * 0.8) {
return Mth.lerp((state.rideVelocity.get().z - (TOP_SPEED * 0.8)) / (TOP_SPEED * 0.2), 1.0, 1.2).toFloat()
}
return 1.0f
}
override fun useAngVelSmoothing(settings: BoatSettings, state: BoatState, vehicle: PokemonEntity): Boolean {
return false
}
override fun useRidingAltPose(
settings: BoatSettings,
state: BoatState,
vehicle: PokemonEntity,
driver: Player
): ResourceLocation {
return cobblemonResource("no_pose")
}
override fun inertia(settings: BoatSettings, state: BoatState, vehicle: PokemonEntity): Double {
return 0.5
}
override fun shouldRoll(settings: BoatSettings, state: BoatState, vehicle: PokemonEntity): Boolean {
return false
}
override fun turnOffOnGround(settings: BoatSettings, state: BoatState, vehicle: PokemonEntity): Boolean {
return false
}
override fun dismountOnShift(settings: BoatSettings, state: BoatState, vehicle: PokemonEntity): Boolean {
return false
}
override fun shouldRotatePokemonHead(
settings: BoatSettings,
state: BoatState,
vehicle: PokemonEntity
): Boolean {
return vehicle.runtime.resolveBoolean(settings.rotatePokemonHead)
}
override fun shouldRotatePlayerHead(
settings: BoatSettings,
state: BoatState,
vehicle: PokemonEntity
): Boolean {
return true
}
override fun maxUpStep(settings: BoatSettings, state: BoatState, vehicle: PokemonEntity) = 0f
override fun createDefaultState(settings: BoatSettings) = BoatState()
}
class BoatSettings : RidingBehaviourSettings {
override val key = BoatBehaviour.KEY
var terminalVelocity = "-2.0".asExpression()
private set
var rotatePokemonHead = "true".asExpression()
private set
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeResourceLocation(key)
buffer.writeExpression(terminalVelocity)
}
override fun decode(buffer: RegistryFriendlyByteBuf) {
terminalVelocity = buffer.readExpression()
}
}
class BoatState : RidingBehaviourState() {
val deltaRotation = ridingState(0.0, Side.CLIENT)
val jumpBuffer = ridingState(-1, Side.CLIENT)
val staminaBuffer = ridingState(0, Side.CLIENT)
override fun copy() = BoatState().also {
it.deltaRotation.set(deltaRotation.get(), true)
it.rideVelocity.set(rideVelocity.get(), true)
it.stamina.set(stamina.get(), true)
it.jumpBuffer.set(jumpBuffer.get(), true)
it.staminaBuffer.set(staminaBuffer.get(), true)
}
override fun shouldSync(previous: RidingBehaviourState): Boolean {
if (previous !is BoatState) return false
return super.shouldSync(previous)
}
}
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding.behaviour.types
package com.cobblemon.mod.common.api.riding.behaviour.types.liquid
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.OrientationControllable
@@ -27,22 +27,22 @@ import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
import net.minecraft.world.phys.shapes.Shapes
class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
class BurstBehaviour : RidingBehaviour<BurstSettings, BurstState> {
companion object {
val KEY = cobblemonResource("swim/dash")
val KEY = cobblemonResource("liquid/burst")
const val DASH_TICKS: Int = 60
}
override val key = KEY
override fun getRidingStyle(settings: SwimDashSettings, state: SwimDashState): RidingStyle {
override fun getRidingStyle(settings: BurstSettings, state: BurstState): RidingStyle {
return RidingStyle.LIQUID
}
val poseProvider = PoseProvider<SwimDashSettings, SwimDashState>(PoseType.FLOAT)
val poseProvider = PoseProvider<BurstSettings, BurstState>(PoseType.FLOAT)
.with(PoseOption(PoseType.SWIM) { _, _, entity -> entity.isSwimming && entity.entityData.get(PokemonEntity.MOVING) })
override fun isActive(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): Boolean {
override fun isActive(settings: BurstSettings, state: BurstState, vehicle: PokemonEntity): Boolean {
//This could be kinda weird... what if the top of the mon is in a fluid but the bottom isnt?
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
if (vehicle.isInWater || vehicle.isUnderWater) {
@@ -53,13 +53,13 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
}
}
override fun pose(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): PoseType {
override fun pose(settings: BurstSettings, state: BurstState, vehicle: PokemonEntity): PoseType {
return poseProvider.select(settings, state, vehicle)
}
override fun speed(
settings: SwimDashSettings,
state: SwimDashState,
settings: BurstSettings,
state: BurstState,
vehicle: PokemonEntity,
driver: Player
): Float {
@@ -77,8 +77,8 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
}
override fun rotation(
settings: SwimDashSettings,
state: SwimDashState,
settings: BurstSettings,
state: BurstState,
vehicle: PokemonEntity,
driver: LivingEntity
): Vec2 {
@@ -86,8 +86,8 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
}
override fun velocity(
settings: SwimDashSettings,
state: SwimDashState,
settings: BurstSettings,
state: BurstState,
vehicle: PokemonEntity,
driver: Player,
input: Vec3
@@ -102,8 +102,8 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
}
override fun angRollVel(
settings: SwimDashSettings,
state: SwimDashState,
settings: BurstSettings,
state: BurstState,
vehicle: PokemonEntity,
driver: Player,
deltaTime: Double
@@ -112,8 +112,8 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
}
override fun rotationOnMouseXY(
settings: SwimDashSettings,
state: SwimDashState,
settings: BurstSettings,
state: BurstState,
vehicle: PokemonEntity,
driver: Player,
mouseY: Double,
@@ -132,8 +132,8 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
}
override fun canJump(
settings: SwimDashSettings,
state: SwimDashState,
settings: BurstSettings,
state: BurstState,
vehicle: PokemonEntity,
driver: Player
): Boolean {
@@ -141,8 +141,8 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
}
override fun setRideBar(
settings: SwimDashSettings,
state: SwimDashState,
settings: BurstSettings,
state: BurstState,
vehicle: PokemonEntity,
driver: Player
): Float {
@@ -150,8 +150,8 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
}
override fun jumpForce(
settings: SwimDashSettings,
state: SwimDashState,
settings: BurstSettings,
state: BurstState,
vehicle: PokemonEntity,
driver: Player,
jumpStrength: Int
@@ -160,8 +160,8 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
}
override fun gravity(
settings: SwimDashSettings,
state: SwimDashState,
settings: BurstSettings,
state: BurstState,
vehicle: PokemonEntity,
regularGravity: Double
): Double {
@@ -169,64 +169,64 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
}
override fun rideFovMultiplier(
settings: SwimDashSettings,
state: SwimDashState,
settings: BurstSettings,
state: BurstState,
vehicle: PokemonEntity,
driver: Player
): Float {
return 1.0f
}
override fun useAngVelSmoothing(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): Boolean {
override fun useAngVelSmoothing(settings: BurstSettings, state: BurstState, vehicle: PokemonEntity): Boolean {
return false
}
override fun useRidingAltPose(
settings: SwimDashSettings,
state: SwimDashState,
settings: BurstSettings,
state: BurstState,
vehicle: PokemonEntity,
driver: Player
): ResourceLocation {
return cobblemonResource("no_pose")
}
override fun inertia(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): Double {
override fun inertia(settings: BurstSettings, state: BurstState, vehicle: PokemonEntity): Double {
return 0.5
}
override fun shouldRoll(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): Boolean {
override fun shouldRoll(settings: BurstSettings, state: BurstState, vehicle: PokemonEntity): Boolean {
return false
}
override fun turnOffOnGround(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): Boolean {
override fun turnOffOnGround(settings: BurstSettings, state: BurstState, vehicle: PokemonEntity): Boolean {
return false
}
override fun dismountOnShift(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): Boolean {
override fun dismountOnShift(settings: BurstSettings, state: BurstState, vehicle: PokemonEntity): Boolean {
return false
}
override fun shouldRotatePokemonHead(
settings: SwimDashSettings,
state: SwimDashState,
settings: BurstSettings,
state: BurstState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun shouldRotatePlayerHead(
settings: SwimDashSettings,
state: SwimDashState,
settings: BurstSettings,
state: BurstState,
vehicle: PokemonEntity
): Boolean {
return false
}
override fun createDefaultState(settings: SwimDashSettings) = SwimDashState()
override fun createDefaultState(settings: BurstSettings) = BurstState()
}
class SwimDashSettings : RidingBehaviourSettings {
override val key = SwimDashBehaviour.KEY
class BurstSettings : RidingBehaviourSettings {
override val key = BurstBehaviour.KEY
var dashSpeed = 1F
private set
@@ -241,7 +241,7 @@ class SwimDashSettings : RidingBehaviourSettings {
}
}
class SwimDashState : RidingBehaviourState() {
class BurstState : RidingBehaviourState() {
var dashing = ridingState(false, Side.BOTH)
var ticks = ridingState(0, Side.BOTH)
@@ -252,10 +252,10 @@ class SwimDashState : RidingBehaviourState() {
}
override fun toString(): String {
return "SwimDashState(dashing=${dashing.get()}, ticks=${ticks.get()})"
return "BurstState(dashing=${dashing.get()}, ticks=${ticks.get()})"
}
override fun copy() = SwimDashState().also {
override fun copy() = BurstState().also {
it.rideVelocity.set(rideVelocity.get(), forced = true)
it.stamina.set(stamina.get(), forced = true)
it.dashing.set(dashing.get(), forced = true)
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.riding.behaviour.types
package com.cobblemon.mod.common.api.riding.behaviour.types.liquid
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.Cobblemon
@@ -32,7 +32,7 @@ import kotlin.math.sin
class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
companion object {
val KEY = cobblemonResource("swim/dolphin")
val KEY = cobblemonResource("liquid/dolphin")
}
override val key = KEY
@@ -8,9 +8,7 @@
package com.cobblemon.mod.common.api.snowstorm
import com.cobblemon.mod.common.api.data.ArbitrarilyMappedSerializableCompanion
import com.cobblemon.mod.common.client.render.MatrixWrapper
import com.cobblemon.mod.common.util.codec.CodecUtils
import com.cobblemon.mod.common.util.codec.optionalFieldOfWithDefault
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
@@ -34,7 +32,11 @@ class EmitterSpace(
}
fun initializeEmitterMatrix(rootMatrix: MatrixWrapper, locatorMatrix: MatrixWrapper): MatrixWrapper {
val rootRotation = rootMatrix.matrix.getRotation(AxisAngle4f())
var rootRotation = rootMatrix.matrix.getRotation(AxisAngle4f())
//When the locator hasn't yet been initialized, we start getting NaNs, so default to no rotation instead
if (rootRotation.x.isNaN() || rootRotation.y.isNaN() || rootRotation.z.isNaN() || rootRotation.angle.isNaN()) {
rootRotation = AxisAngle4f()
}
val scale = Vector3f()
if (scaling == ScalingMode.ENTITY) {
@@ -14,11 +14,16 @@ import com.bedrockk.molang.ast.NumberExpression
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.api.codec.CodecMapped
import com.cobblemon.mod.common.api.data.ArbitrarilyMappedSerializableCompanion
import com.cobblemon.mod.common.util.*
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.codec.EXPRESSION_CODEC
import com.cobblemon.mod.common.util.getString
import com.cobblemon.mod.common.util.math.convertSphericalToCartesian
import com.cobblemon.mod.common.util.math.getRotationMatrix
import com.cobblemon.mod.common.util.math.times
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.resolveDouble
import com.cobblemon.mod.common.util.resolveVec3d
import com.cobblemon.mod.common.util.writeString
import com.mojang.serialization.Codec
import com.mojang.serialization.DataResult
import com.mojang.serialization.DynamicOps
@@ -27,10 +32,10 @@ import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.world.entity.Entity
import net.minecraft.world.phys.AABB
import net.minecraft.world.phys.Vec3
import kotlin.math.cos
import kotlin.math.sin
import kotlin.random.Random
import net.minecraft.world.phys.Vec3
interface ParticleEmitterShape : CodecMapped {
companion object : ArbitrarilyMappedSerializableCompanion<ParticleEmitterShape, ParticleEmitterShapeType>(
@@ -261,9 +266,9 @@ class BoxParticleEmitterShape(
}
} else {
Vec3(
Random.nextDouble(sizes.x) - sizes.x / 2,
Random.nextDouble(sizes.y) - sizes.y / 2,
Random.nextDouble(sizes.z) - sizes.z / 2
Random.nextDouble(sizes.x) - sizes.x / 2.0,
Random.nextDouble(sizes.y) - sizes.y / 2.0,
Random.nextDouble(sizes.z) - sizes.z / 2.0
)
}
@@ -18,29 +18,30 @@ 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
import com.cobblemon.mod.common.api.spawning.context.LavafloorSpawningContext
import com.cobblemon.mod.common.api.spawning.context.SeafloorSpawningContext
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.context.SubmergedSpawningContext
import com.cobblemon.mod.common.api.spawning.context.SurfaceSpawningContext
import com.cobblemon.mod.common.api.spawning.context.calculators.GroundedSpawningContextCalculator
import com.cobblemon.mod.common.api.spawning.context.calculators.LavafloorSpawningContextCalculator
import com.cobblemon.mod.common.api.spawning.context.calculators.SeafloorSpawningContextCalculator
import com.cobblemon.mod.common.api.spawning.context.calculators.SpawningContextCalculator
import com.cobblemon.mod.common.api.spawning.context.calculators.SubmergedSpawningContextCalculator
import com.cobblemon.mod.common.api.spawning.context.calculators.SurfaceSpawningContextCalculator
import com.cobblemon.mod.common.api.spawning.position.calculators.GroundedSpawnablePositionCalculator
import com.cobblemon.mod.common.api.spawning.position.calculators.LavafloorSpawnablePositionCalculator
import com.cobblemon.mod.common.api.spawning.position.calculators.SeafloorSpawnablePositionCalculator
import com.cobblemon.mod.common.api.spawning.position.calculators.SpawnablePositionCalculator
import com.cobblemon.mod.common.api.spawning.position.calculators.SubmergedSpawnablePositionCalculator
import com.cobblemon.mod.common.api.spawning.position.calculators.SurfaceSpawnablePositionCalculator
import com.cobblemon.mod.common.api.spawning.detail.NPCSpawnDetail
import com.cobblemon.mod.common.api.spawning.detail.PokemonHerdSpawnDetail
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawner
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.api.spawning.position.AreaSpawnablePositionResolver
import com.cobblemon.mod.common.api.spawning.position.FishingSpawnablePosition
import com.cobblemon.mod.common.api.spawning.position.GroundedSpawnablePosition
import com.cobblemon.mod.common.api.spawning.position.LavafloorSpawnablePosition
import com.cobblemon.mod.common.api.spawning.position.SeafloorSpawnablePosition
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import com.cobblemon.mod.common.api.spawning.position.SubmergedSpawnablePosition
import com.cobblemon.mod.common.api.spawning.position.SurfaceSpawnablePosition
import com.cobblemon.mod.common.api.spawning.preset.BasicSpawnDetailPreset
import com.cobblemon.mod.common.api.spawning.preset.BestSpawnerConfig
import com.cobblemon.mod.common.api.spawning.preset.PokemonSpawnDetailPreset
import com.cobblemon.mod.common.api.spawning.prospecting.SpawningProspector
import com.cobblemon.mod.common.api.spawning.selection.SpawningSelector
import com.cobblemon.mod.common.api.spawning.spawner.AreaSpawner
import com.cobblemon.mod.common.api.spawning.spawner.FixedAreaSpawner
@@ -57,12 +58,12 @@ import net.minecraft.server.MinecraftServer
* the configuration and many other properties used by the spawner.
*
* The Best Spawner (in world spawning) works in distinct stages that are:
* - Prospecting (see: [SpawningProspector])
* - Context resolving (see: [AreaContextResolver])
* - Spawning zone generation (see: [SpawningZoneGenerator])
* - Spawnable position resolving (see: [AreaSpawnablePositionResolver])
* - Spawn selection (see: [SpawningSelector])
* - Spawn action (see: [SpawnAction])
*
* In the case of more specialized use, the creation of a [SpawningContext] that motivates most of the spawn
* In the case of more specialized use, the creation of a [SpawnablePosition] that motivates most of the spawn
* process can be created manually, skipping the first two steps.
*
* An individually spawnable entity is defined as a [SpawnDetail]. A processor handling this process is a [Spawner].
@@ -74,10 +75,10 @@ import net.minecraft.server.MinecraftServer
* Spawning is coordinated and ticked using a [SpawnerManager], and all the current managers are accessible from
* [BestSpawner.spawnerManagers].
*
* Spawners and contexts are often put under the effects of [SpawningInfluence]s which can be used to make temporary
* or lasting changes to spawning for whatever component they are attached to (whether that is a spawner or a context).
* This pairs strongly with edits to the influence builders inside the [PlayerSpawnerFactory]. The range of effects
* an influence can have is significant.
* Spawners and spawnable positions are often put under the effects of [SpawningInfluence]s which can be used to make
* temporary or lasting changes to spawning for whatever component they are attached to (whether that is a spawner or a
* spawnable position). This pairs strongly with edits to the influence builders inside the [PlayerSpawnerFactory]. The
* range of effects an influence can exert is very broad.
*
* Broad configuration of this spawning system is found in [BestSpawner.config].
*
@@ -87,7 +88,7 @@ import net.minecraft.server.MinecraftServer
object BestSpawner {
var config = BestSpawnerConfig()
val spawnerManagers = mutableListOf<SpawnerManager>(CobblemonWorldSpawnerManager)
var defaultPokemonDespawner: Despawner<PokemonEntity> = CobblemonAgingDespawner(getAgeTicks = { it.ticksLived })
lateinit var defaultPokemonDespawner: Despawner<PokemonEntity>
lateinit var fishingSpawner: FishingSpawner
fun init() {
@@ -103,23 +104,24 @@ object BestSpawner {
LOGGER.info("Loaded ${SpawningCondition.conditionTypes.size} spawning condition types.")
SpawningContextCalculator.register(GroundedSpawningContextCalculator)
SpawningContextCalculator.register(SeafloorSpawningContextCalculator)
SpawningContextCalculator.register(LavafloorSpawningContextCalculator)
SpawningContextCalculator.register(SubmergedSpawningContextCalculator)
SpawningContextCalculator.register(SurfaceSpawningContextCalculator)
SpawnablePositionCalculator.register(GroundedSpawnablePositionCalculator)
SpawnablePositionCalculator.register(SeafloorSpawnablePositionCalculator)
SpawnablePositionCalculator.register(LavafloorSpawnablePositionCalculator)
SpawnablePositionCalculator.register(SubmergedSpawnablePositionCalculator)
SpawnablePositionCalculator.register(SurfaceSpawnablePositionCalculator)
SpawningContext.register(name = "grounded", clazz = GroundedSpawningContext::class.java, defaultCondition = GroundedSpawningCondition.NAME)
SpawningContext.register(name = "seafloor", clazz = SeafloorSpawningContext::class.java, defaultCondition = SeafloorSpawningCondition.NAME)
SpawningContext.register(name = "lavafloor", clazz = LavafloorSpawningContext::class.java, defaultCondition = GroundedSpawningCondition.NAME)
SpawningContext.register(name = "submerged", clazz = SubmergedSpawningContext::class.java, defaultCondition = SubmergedSpawningCondition.NAME)
SpawningContext.register(name = "surface", clazz = SurfaceSpawningContext::class.java, defaultCondition = SurfaceSpawningCondition.NAME)
SpawningContext.register(name = "fishing", clazz = FishingSpawningContext::class.java, defaultCondition = FishingSpawningCondition.NAME)
SpawnablePosition.register(name = "grounded", clazz = GroundedSpawnablePosition::class.java, defaultCondition = GroundedSpawningCondition.NAME)
SpawnablePosition.register(name = "seafloor", clazz = SeafloorSpawnablePosition::class.java, defaultCondition = SeafloorSpawningCondition.NAME)
SpawnablePosition.register(name = "lavafloor", clazz = LavafloorSpawnablePosition::class.java, defaultCondition = GroundedSpawningCondition.NAME)
SpawnablePosition.register(name = "submerged", clazz = SubmergedSpawnablePosition::class.java, defaultCondition = SubmergedSpawningCondition.NAME)
SpawnablePosition.register(name = "surface", clazz = SurfaceSpawnablePosition::class.java, defaultCondition = SurfaceSpawningCondition.NAME)
SpawnablePosition.register(name = "fishing", clazz = FishingSpawnablePosition::class.java, defaultCondition = FishingSpawningCondition.NAME)
LOGGER.info("Loaded ${SpawningContext.contexts.size} spawning context types.")
LOGGER.info("Loaded ${SpawnablePosition.spawnablePositionTypes.size} spawnable position types.")
SpawnDetail.registerSpawnType(name = PokemonSpawnDetail.TYPE, PokemonSpawnDetail::class.java)
SpawnDetail.registerSpawnType(name = NPCSpawnDetail.TYPE, NPCSpawnDetail::class.java)
SpawnDetail.registerSpawnType(name = PokemonHerdSpawnDetail.TYPE, PokemonHerdSpawnDetail::class.java)
LOGGER.info("Loaded ${SpawnDetail.spawnDetailTypes.size} spawn detail types.")
loadConfig()
@@ -129,6 +131,7 @@ object BestSpawner {
}
fun loadConfig() {
defaultPokemonDespawner = CobblemonAgingDespawner(getAgeTicks = { it.ticksLived })
config = BestSpawnerConfig.load()
}
@@ -142,4 +145,4 @@ object BestSpawner {
spawnerManagers.forEach(SpawnerManager::onServerStarted)
fishingSpawner = FishingSpawner()
}
}
}
@@ -11,7 +11,7 @@ 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.condition.SpawnablePositionTypePrecalculation
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.data.CobblemonDataProvider
import net.minecraft.server.MinecraftServer
@@ -31,7 +31,7 @@ object CobblemonSpawnPools {
fun load() {
WORLD_SPAWN_POOL = CobblemonDataProvider.register(SpawnPool("world")
.addPrecalculators(
ContextPrecalculation,
SpawnablePositionTypePrecalculation,
BucketPrecalculation,
BiomePrecalculation
)
@@ -39,7 +39,7 @@ object CobblemonSpawnRules : JsonDataRegistry<SpawnRule> {
override val gson = GsonBuilder()
.registerTypeAdapter(SpawnRuleComponent::class.java, SpawnRuleComponentAdapter)
.registerTypeAdapter(SpawnDetailSelector::class.java, SpawnDetailSelectorAdapter)
.registerTypeAdapter(SpawningContextSelector::class.java, SpawningContextSelectorAdapter)
.registerTypeAdapter(SpawnablePositionSelector::class.java, SpawnablePositionSelectorAdapter)
.registerTypeAdapter(SpawningCondition::class.java, SpawningConditionAdapter)
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
@@ -56,8 +56,8 @@ object CobblemonSpawnRules : JsonDataRegistry<SpawnRule> {
SpawnDetailSelector.register<ExpressionSpawnDetailSelector>("expression")
SpawningContextSelector.register<ExpressionSpawningContextSelector>("expression")
SpawningContextSelector.register<ConditionalSpawningContextSelector>("conditional")
SpawnablePositionSelector.register<ExpressionSpawnablePositionSelector>("expression")
SpawnablePositionSelector.register<ConditionalSpawnablePositionSelector>("conditional")
}
val rules = mutableMapOf<ResourceLocation, SpawnRule>()
@@ -10,11 +10,10 @@ package com.cobblemon.mod.common.api.spawning
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.Cobblemon.config
import com.cobblemon.mod.common.api.spawning.influence.WorldSlicedSpawningInfluence
import com.cobblemon.mod.common.api.spawning.prospecting.SpawningInfluenceProspector
import com.cobblemon.mod.common.api.spawning.prospecting.SpawningProspector
import com.cobblemon.mod.common.api.spawning.influence.SpawningZoneInfluence
import com.cobblemon.mod.common.api.spawning.influence.detector.SpawningInfluenceDetector
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
import com.cobblemon.mod.common.api.spawning.spawner.SpawningArea
import com.cobblemon.mod.common.api.spawning.spawner.SpawningZoneInput
import com.cobblemon.mod.common.api.tags.CobblemonBlockTags
import net.minecraft.core.BlockPos
import net.minecraft.core.SectionPos.blockToSectionCoord
@@ -27,21 +26,21 @@ import net.minecraft.world.phys.AABB
import net.minecraft.world.phys.Vec3
/**
* A spawning prospector that takes a straightforward approach
* in slicing out a [WorldSlice]. If you want to replace this,
* change over the value of [Cobblemon.prospector].
* A spawning zone generator that takes a straightforward approach
* in slicing out a [SpawningZone]. If you want to replace this,
* change over the value of [Cobblemon.spawningZoneGenerator].
*
* @author Hiroku
* @since February 5th, 2022
*/
object CobblemonSpawningProspector : SpawningProspector {
override fun prospect(
object CobblemonSpawningZoneGenerator : SpawningZoneGenerator {
override fun generate(
spawner: Spawner,
area: SpawningArea
): WorldSlice {
val world = area.world
var baseY = area.baseY
var height = area.height
input: SpawningZoneInput
): SpawningZone {
val world = input.world
var baseY = input.baseY
var height = input.height
if (baseY < world.minBuildHeight) {
val difference = world.minBuildHeight - baseY
baseY += difference
@@ -60,34 +59,34 @@ object CobblemonSpawningProspector : SpawningProspector {
}
val minimumDistanceBetweenEntities = config.minimumDistanceBetweenEntities
val nearbyEntityPositions = area.world.getEntities(
area.cause.entity,
val nearbyEntityPositions = input.world.getEntities(
input.cause.entity,
AABB.ofSize(
Vec3(
area.baseX + area.length / 2.0,
input.baseX + input.length / 2.0,
baseY + height / 2.0,
area.baseZ + area.width / 2.0
input.baseZ + input.width / 2.0
),
area.length + minimumDistanceBetweenEntities,
input.length + minimumDistanceBetweenEntities,
height + minimumDistanceBetweenEntities,
area.width + minimumDistanceBetweenEntities
input.width + minimumDistanceBetweenEntities
)
).filterIsInstance<LivingEntity>()
.map { it.position() }
val defaultState = Blocks.STONE.defaultBlockState()
val defaultBlockData = WorldSlice.BlockData(defaultState, 0, 0)
val defaultBlockData = SpawningZone.BlockData(defaultState, 0, 0)
val blocks = Array(area.length) { Array(height) { Array(area.width) { defaultBlockData } } }
val skyLevel = Array(area.length) { Array(area.width) { world.maxBuildHeight } }
val blocks = Array(input.length) { Array(height) { Array(input.width) { defaultBlockData } } }
val skyLevel = Array(input.length) { Array(input.width) { world.maxBuildHeight } }
val pos = BlockPos.MutableBlockPos()
val worldSlicedSpawningInfluences = mutableListOf<WorldSlicedSpawningInfluence>()
val spawningZoneInfluences = mutableListOf<SpawningZoneInfluence>()
val chunks = mutableMapOf<Pair<Int, Int>, ChunkAccess?>()
val yRange = (baseY until baseY + height).reversed()
val lightingProvider = world.lightEngine
for (x in area.baseX until area.baseX + area.length) {
for (z in area.baseZ until area.baseZ + area.width) {
for (x in input.baseX until input.baseX + input.length) {
for (z in input.baseZ until input.baseZ + input.width) {
val query = chunks.computeIfAbsent(Pair(blockToSectionCoord(x), blockToSectionCoord(z))) {
world.getChunk(it.first, it.second, ChunkStatus.FULL, false)
} ?: continue
@@ -96,14 +95,14 @@ object CobblemonSpawningProspector : SpawningProspector {
for (y in yRange) {
val skyLight = lightingProvider.getLayerListener(LightLayer.SKY).getLightValue(pos.set(x, y, z))
val state = query.getBlockState(pos.set(x, y, z))
blocks[x - area.baseX][y - baseY][z - area.baseZ] = WorldSlice.BlockData(
blocks[x - input.baseX][y - baseY][z - input.baseZ] = SpawningZone.BlockData(
state = state,
light = world.getMaxLocalRawBrightness(pos),
skyLight = skyLight
)
worldSlicedSpawningInfluences.addAll(SpawningInfluenceProspector.prospectors.mapNotNull { it.prospectBlock(world, pos, state) })
spawningZoneInfluences.addAll(SpawningInfluenceDetector.detectors.flatMap { it.detectFromBlock(world, pos, state) })
if (canSeeSky) {
skyLevel[x - area.baseX][z - area.baseZ] = y
skyLevel[x - input.baseX][z - input.baseZ] = y
}
if (state.fluidState.isEmpty && !state.`is`(CobblemonBlockTags.SEES_SKY)) {
canSeeSky = false
@@ -112,20 +111,20 @@ object CobblemonSpawningProspector : SpawningProspector {
}
}
for (prospector in SpawningInfluenceProspector.prospectors) {
worldSlicedSpawningInfluences.addAll(prospector.prospect(spawner, area))
for (spawningZoneGenerator in SpawningInfluenceDetector.detectors) {
spawningZoneInfluences.addAll(spawningZoneGenerator.detectFromInput(spawner, input))
}
return WorldSlice(
cause = area.cause,
return SpawningZone(
cause = input.cause,
world = world,
baseX = area.baseX,
baseX = input.baseX,
baseY = baseY,
baseZ = area.baseZ,
baseZ = input.baseZ,
blocks = blocks,
skyLevel = skyLevel,
nearbyEntityPositions = nearbyEntityPositions,
influences = worldSlicedSpawningInfluences
influences = spawningZoneInfluences
)
}
}
@@ -12,7 +12,6 @@ import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory
import com.cobblemon.mod.common.platform.events.PlatformEvents
import com.cobblemon.mod.common.util.server
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
import net.minecraft.server.level.ServerLevel
import java.util.UUID
@@ -9,8 +9,8 @@
package com.cobblemon.mod.common.api.spawning
/**
* A spawn bucket is a simple referenceable object by spawn files. The bucket is used early in the spawn
* process to decide which set of spawns will be used for spawning on that attempt. Weights are used to
* A spawn bucket is a simple referenceable object by spawn files. The bucket is used at the beginning of
* the selection process to decide which set of spawns will be used for spawning on that attempt. Weights are used to
* make entire buckets more or less likely, and then weighted selections will occur within whichever bucket
* was chosen.
*
@@ -1,32 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.util.weightedSelection
object SpawnBucketUtils {
fun chooseAdjustedSpawnBucket(buckets: List<SpawnBucket>, bucketLureStrength: Int): SpawnBucket {
val baseValues = listOf(88.5F, 8.5F, 2.4F, 0.6F)
val adjustments = listOf(-6.9F, 3.6F, 2.3F, 1F)
val adjustedWeights = buckets.mapIndexed { index, bucket ->
if (index >= baseValues.size) {
bucket to bucket.weight
} else {
val base = baseValues[index]
val adjustment = adjustments[index]
val adjusted = base + adjustment * bucketLureStrength
bucket to adjusted.coerceAtLeast(0f) // we do not want the weights to be negative
}
}.toMap()
return buckets.weightedSelection { adjustedWeights[it]!! }!!
}
}
@@ -16,7 +16,6 @@ import net.minecraft.world.entity.EntityType
open class SpawnCause(
val spawner: Spawner,
val bucket: SpawnBucket,
entity: Entity? = null
): SpawningInfluence {
val entityWorldId = entity?.level()?.dimension()
@@ -25,5 +24,9 @@ open class SpawnCause(
val entityType = entity?.type
val entity: Entity?
get() = if (entityType == EntityType.PLAYER) server()?.playerList?.getPlayer(entityUUID) else server()?.getLevel(entityWorldId)?.getEntity(entityId!!)
get() = if (entityType == EntityType.PLAYER) {
server()?.playerList?.getPlayer(entityUUID!!)
} else {
server()?.getLevel(entityWorldId!!)?.getEntity(entityId!!)
}
}
@@ -17,7 +17,7 @@ import com.cobblemon.mod.common.api.npc.NPCClass
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
import com.cobblemon.mod.common.api.spawning.context.RegisteredSpawningContext
import com.cobblemon.mod.common.api.spawning.position.SpawnablePositionType
import com.cobblemon.mod.common.api.spawning.detail.PossibleHeldItem
import com.cobblemon.mod.common.api.spawning.preset.SpawnDetailPreset
import com.cobblemon.mod.common.util.adapters.*
@@ -50,7 +50,7 @@ object SpawnDetailPresets : JsonDataRegistry<SpawnDetailPreset> {
.setLenient()
.disableHtmlEscaping()
.registerTypeAdapter(SpawnBucket::class.java, SpawnBucketAdapter)
.registerTypeAdapter(RegisteredSpawningContext::class.java, RegisteredSpawningContextAdapter)
.registerTypeAdapter(SpawnablePositionType::class.java, RegisteredSpawnablePositionAdapter)
.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, Fluid::class.java).type, FluidLikeConditionAdapter)
@@ -16,7 +16,7 @@ import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.npc.NPCClass
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
import com.cobblemon.mod.common.api.spawning.context.RegisteredSpawningContext
import com.cobblemon.mod.common.api.spawning.position.SpawnablePositionType
import com.cobblemon.mod.common.api.spawning.detail.PossibleHeldItem
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import com.cobblemon.mod.common.util.adapters.*
@@ -58,7 +58,7 @@ object SpawnLoader {
).type,
EitherIdentifierOrTagAdapter(Registries.STRUCTURE)
)
.registerTypeAdapter(RegisteredSpawningContext::class.java, RegisteredSpawningContextAdapter)
.registerTypeAdapter(SpawnablePositionType::class.java, RegisteredSpawnablePositionAdapter)
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.registerTypeAdapter(SpawnDetail::class.java, SpawnDetailAdapter)
.registerTypeAdapter(DropEntry::class.java, DropEntryAdapter)
@@ -8,28 +8,29 @@
package com.cobblemon.mod.common.api.spawning
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.influence.ConditionalSpawningZoneInfluence
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.api.spawning.influence.WorldSlicedSpawningInfluence
import com.cobblemon.mod.common.api.spawning.prospecting.SpawningProspector
import com.cobblemon.mod.common.api.spawning.influence.UnconditionalSpawningZoneInfluence
import com.cobblemon.mod.common.api.spawning.influence.SpawningZoneInfluence
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import kotlin.math.max
import net.minecraft.core.BlockPos
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.level.ChunkPos
import net.minecraft.world.level.block.Blocks
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.Vec3
import kotlin.math.max
/**
* A slice of the world that can be accessed safely from an async thread. This includes all of the information
* A zone of the world that can be accessed quickly from later steps. This includes all the information
* that might be unsafe to access async from the world itself for the purposes of spawning.
*
* This is generated by a [SpawningProspector].
* This is generated by a [SpawningZoneGenerator].
*
* @author Hiroku
* @since January 31st, 2022
*/
class WorldSlice(
class SpawningZone(
val cause: SpawnCause,
val world: ServerLevel,
val baseX: Int,
@@ -38,7 +39,7 @@ class WorldSlice(
val blocks: Array<Array<Array<BlockData>>>,
val skyLevel: Array<Array<Int>>,
var nearbyEntityPositions: List<Vec3>,
val influences: List<WorldSlicedSpawningInfluence>
influences: List<SpawningZoneInfluence>
) {
class BlockData(
val state: BlockState,
@@ -46,14 +47,17 @@ class WorldSlice(
val skyLight: Int
)
val unconditionalInfluences = influences.filterIsInstance<UnconditionalSpawningZoneInfluence>().map { it.influence }
val conditionalInfluences = influences.filterIsInstance<ConditionalSpawningZoneInfluence>()
val length = blocks.size
val height = blocks[0].size
val width = blocks[0][0].size
private val structureChunkCaches = mutableMapOf<ChunkPos, SpawningContext.StructureChunkCache>()
private val structureChunkCaches = mutableMapOf<ChunkPos, SpawnablePosition.StructureChunkCache>()
fun getStructureCache(pos: BlockPos): SpawningContext.StructureChunkCache {
return structureChunkCaches.getOrPut(ChunkPos(pos), SpawningContext::StructureChunkCache)
fun getStructureCache(pos: BlockPos): SpawnablePosition.StructureChunkCache {
return structureChunkCaches.getOrPut(ChunkPos(pos), SpawnablePosition::StructureChunkCache)
}
companion object {
@@ -228,4 +232,8 @@ class WorldSlice(
return space
}
fun getInfluences(spawnablePosition: SpawnablePosition): List<SpawningInfluence> {
return unconditionalInfluences + conditionalInfluences.filter { it.appliesTo(spawnablePosition) }.map { it.influence }
}
}
@@ -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.spawning
import com.cobblemon.mod.common.api.spawning.position.AreaSpawnablePosition
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
import com.cobblemon.mod.common.api.spawning.spawner.SpawningZoneInput
/**
* Interface responsible for slicing out an async-save [SpawningZone] that can be used for generating
* [SpawnablePosition]s, specifically [AreaSpawnablePosition]s.
*
* @author Hiroku
* @since January 29th, 2022
*/
interface SpawningZoneGenerator {
fun generate(spawner: Spawner, input: SpawningZoneInput): SpawningZone
}
@@ -8,8 +8,7 @@
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 com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import com.cobblemon.mod.common.util.adapters.SpawningConditionAdapter
/**
@@ -17,7 +16,7 @@ import com.cobblemon.mod.common.util.adapters.SpawningConditionAdapter
* and is then stowed in [SpawningCondition.appendages].
*
* As an example, you could add an appendage which has a single field called 'weather'. The [fits]
* implementation would check the [SpawningContext] using your own logic. Inside the JSON, you
* implementation would check the [SpawnablePosition] using your own logic. Inside the JSON, you
* would specify the 'weather' property as if it was a built-in field inside [SpawningCondition]. During
* loading, it will deserialize the [SpawningCondition]'s JSON several times targeting the various
* appendage classes, and then add those appendages to [SpawningCondition.appendages] so that when
@@ -55,5 +54,5 @@ interface AppendageCondition {
fun getAppendages(spawningCondition: SpawningCondition<*>) = appendages.filter { it.spawningConditionFits(spawningCondition) }.map { it.clazz }
}
fun fits(ctx: SpawningContext): Boolean
fun fits(spawnablePosition: SpawnablePosition): Boolean
}
@@ -9,30 +9,30 @@
package com.cobblemon.mod.common.api.spawning.condition
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
import com.cobblemon.mod.common.api.spawning.context.AreaSpawningContext
import com.cobblemon.mod.common.api.spawning.position.AreaSpawnablePosition
import com.cobblemon.mod.common.util.Merger
import net.minecraft.world.level.block.Block
/**
* Base type for a spawning condition that applies to some kind of [AreaSpawningContext]. This
* can be extended for subclasses of [AreaSpawningContext].
* Base type for a spawning condition that applies to some kind of [AreaSpawnablePosition]. This
* can be extended for subclasses of [AreaSpawnablePosition].
*
* @author Hiroku
* @since February 7th, 2022
*/
abstract class AreaTypeSpawningCondition<T : AreaSpawningContext> : SpawningCondition<T>() {
abstract class AreaTypeSpawningCondition<T : AreaSpawnablePosition> : SpawningCondition<T>() {
var minHeight: Int? = null
var maxHeight: Int? = null
var neededNearbyBlocks: MutableList<RegistryLikeCondition<Block>>? = null
override fun fits(ctx: T): Boolean {
if (!super.fits(ctx)) {
override fun fits(spawnablePosition: T): Boolean {
if (!super.fits(spawnablePosition)) {
return false
} else if (minHeight != null && ctx.height < minHeight!!) {
} else if (minHeight != null && spawnablePosition.height < minHeight!!) {
return false
} else if (maxHeight != null && ctx.height > maxHeight!!) {
} else if (maxHeight != null && spawnablePosition.height > maxHeight!!) {
return false
} else if (neededNearbyBlocks != null && neededNearbyBlocks!!.none { cond -> ctx.nearbyBlockHolders.any { cond.fits(it) } }) {
} else if (neededNearbyBlocks != null && neededNearbyBlocks!!.none { cond -> spawnablePosition.nearbyBlockHolders.any { cond.fits(it) } }) {
return false
} else {
return true
@@ -49,19 +49,19 @@ abstract class AreaTypeSpawningCondition<T : AreaSpawningContext> : SpawningCond
}
override fun isValid(): Boolean {
val containsNullValues = neededNearbyBlocks != null && neededNearbyBlocks!!.any {it == null}
val containsNullValues = neededNearbyBlocks != null && neededNearbyBlocks!!.any { it == null }
return super.isValid() && !containsNullValues
}
}
/**
* A spawning condition for an [AreaSpawningContext].
* A spawning condition for an [AreaSpawnablePosition].
*
* @author Hiroku
* @since February 7th, 2022
*/
class AreaSpawningCondition : AreaTypeSpawningCondition<AreaSpawningContext>() {
override fun contextClass(): Class<out AreaSpawningContext> = AreaSpawningContext::class.java
class AreaSpawningCondition : AreaTypeSpawningCondition<AreaSpawnablePosition>() {
override fun spawnablePositionClass(): Class<out AreaSpawnablePosition> = AreaSpawnablePosition::class.java
companion object {
const val NAME = "area"
}
@@ -8,16 +8,16 @@
package com.cobblemon.mod.common.api.spawning.condition
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
/**
* A basic spawning condition that works for any type of spawning context.
* A basic spawning condition that works for any type of spawnable position.
*
* @author Hiroku
* @since February 7th, 2022
*/
class BasicSpawningCondition : SpawningCondition<SpawningContext>() {
override fun contextClass(): Class<out SpawningContext> = SpawningContext::class.java
class BasicSpawningCondition : SpawningCondition<SpawnablePosition>() {
override fun spawnablePositionClass(): Class<out SpawnablePosition> = SpawnablePosition::class.java
companion object {
const val NAME = "basic"
}
@@ -8,8 +8,7 @@
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 com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import net.minecraft.core.Holder
import net.minecraft.world.level.biome.Biome
@@ -41,11 +40,11 @@ class CompositeSpawningCondition {
return false
}
fun satisfiedBy(ctx: SpawningContext): Boolean {
return if (conditions.isNotEmpty() && conditions.none { it.isSatisfiedBy(ctx) }) {
fun satisfiedBy(spawnablePosition: SpawnablePosition): Boolean {
return if (conditions.isNotEmpty() && conditions.none { it.isSatisfiedBy(spawnablePosition) }) {
false
} else {
!(anticonditions.isNotEmpty() && anticonditions.any { it.isSatisfiedBy(ctx) })
!(anticonditions.isNotEmpty() && anticonditions.any { it.isSatisfiedBy(spawnablePosition) })
}
}
}
@@ -9,7 +9,7 @@
package com.cobblemon.mod.common.api.spawning.condition
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
import com.cobblemon.mod.common.api.spawning.context.FishingSpawningContext
import com.cobblemon.mod.common.api.spawning.position.FishingSpawnablePosition
import com.cobblemon.mod.common.util.itemRegistry
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.Item
@@ -18,13 +18,13 @@ import net.minecraft.world.item.enchantment.Enchantments
import net.minecraft.world.level.block.Block
/**
* A spawning condition that applies to [FishingSpawningContext]s.
* A spawning condition that applies to [FishingSpawnablePosition]s.
*
* @author Hiroku
* @since February 3rd, 2024
*/
class FishingSpawningCondition: SpawningCondition<FishingSpawningContext>() {
override fun contextClass() = FishingSpawningContext::class.java
class FishingSpawningCondition: SpawningCondition<FishingSpawnablePosition>() {
override fun spawnablePositionClass() = FishingSpawnablePosition::class.java
var rod: RegistryLikeCondition<Item>? = null
var neededNearbyBlocks: MutableList<RegistryLikeCondition<Block>>? = null
@@ -33,19 +33,19 @@ class FishingSpawningCondition: SpawningCondition<FishingSpawningContext>() {
var bait: ResourceLocation? = null
var rodType: ResourceLocation? = null
override fun fits(ctx: FishingSpawningContext): Boolean {
if (!super.fits(ctx)) {
override fun fits(spawnablePosition: FishingSpawnablePosition): Boolean {
if (!super.fits(spawnablePosition)) {
return false
} else if (rod != null && !rod!!.fits(ctx.rodItem ?: return false, ctx.world.itemRegistry)) {
} else if (rod != null && !rod!!.fits(spawnablePosition.rodItem ?: return false, spawnablePosition.world.itemRegistry)) {
return false
} else if (neededNearbyBlocks != null && neededNearbyBlocks!!.none { cond -> ctx.nearbyBlockTypes.any { cond.fits(it, ctx.blockRegistry) } }) {
} else if (neededNearbyBlocks != null && neededNearbyBlocks!!.none { cond -> spawnablePosition.nearbyBlockTypes.any { cond.fits(it, spawnablePosition.blockRegistry) } }) {
return false
}
if (minLureLevel != null) { // check for the lureLevel of the rod
val pokerodStack = ctx.rodStack
val pokerodStack = spawnablePosition.rodStack
val lureLevel = EnchantmentHelper.getItemEnchantmentLevel(
ctx.enchantmentRegistry.getHolder(Enchantments.LURE).get(),
spawnablePosition.enchantmentRegistry.getHolder(Enchantments.LURE).get(),
pokerodStack
)
if (lureLevel < minLureLevel!!) {
@@ -55,13 +55,13 @@ class FishingSpawningCondition: SpawningCondition<FishingSpawningContext>() {
}
}
if (bait != null) { // check for the bait on the bobber
val pokerodBait = ctx.baitStack.itemHolder.unwrapKey().orElse(null)?.location()
val pokerodBait = spawnablePosition.baitStack.itemHolder.unwrapKey().orElse(null)?.location()
if (pokerodBait != bait) {
return false
}
}
if (rodType != null) { // check for the type of pokerod being used
val pokerodItem = ctx.rodItem
val pokerodItem = spawnablePosition.rodItem
if (pokerodItem?.pokeRodId != rodType) {
return false
}
@@ -9,28 +9,28 @@
package com.cobblemon.mod.common.api.spawning.condition
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
import com.cobblemon.mod.common.api.spawning.context.GroundedSpawningContext
import com.cobblemon.mod.common.api.spawning.position.GroundedSpawnablePosition
import com.cobblemon.mod.common.util.Merger
import net.minecraft.world.level.block.Block
/**
* Base type for a spawning condition that applies to some kind of [GroundedSpawningContext]. This
* can be extended for subclasses of [GroundedSpawningContext].
* Base type for a spawning condition that applies to some kind of [GroundedSpawnablePosition]. This
* can be extended for subclasses of [GroundedSpawnablePosition].
*
* @author Hiroku
* @since February 7th, 2022
*/
abstract class GroundedTypeSpawningCondition<T : GroundedSpawningContext> : AreaTypeSpawningCondition<T>() {
abstract class GroundedTypeSpawningCondition<T : GroundedSpawnablePosition> : AreaTypeSpawningCondition<T>() {
var neededBaseBlocks: MutableList<RegistryLikeCondition<Block>>? = null
override fun fits(ctx: T): Boolean {
return if (!super.fits(ctx)) {
override fun fits(spawnablePosition: T): Boolean {
return if (!super.fits(spawnablePosition)) {
false
} else if (minHeight != null && ctx.height < minHeight!!) {
} else if (minHeight != null && spawnablePosition.height < minHeight!!) {
return false
} else if (maxHeight != null && ctx.height > maxHeight!!) {
} else if (maxHeight != null && spawnablePosition.height > maxHeight!!) {
return false
} else if (neededBaseBlocks != null && neededBaseBlocks!!.none { it.fits(ctx.baseBlockHolder) }) {
} else if (neededBaseBlocks != null && neededBaseBlocks!!.none { it.fits(spawnablePosition.baseBlockHolder) }) {
return false
} else {
return true
@@ -51,13 +51,13 @@ abstract class GroundedTypeSpawningCondition<T : GroundedSpawningContext> : Area
}
/**
* A spawning condition for a [GroundedSpawningContext].
* A spawning condition for a [GroundedSpawnablePosition].
*
* @author Hiroku
* @since February 7th, 2022
*/
open class GroundedSpawningCondition : GroundedTypeSpawningCondition<GroundedSpawningContext>() {
override fun contextClass() = GroundedSpawningContext::class.java
open class GroundedSpawningCondition : GroundedTypeSpawningCondition<GroundedSpawnablePosition>() {
override fun spawnablePositionClass() = GroundedSpawnablePosition::class.java
companion object {
const val NAME = "grounded"
}
@@ -9,31 +9,31 @@
package com.cobblemon.mod.common.api.spawning.condition
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
import com.cobblemon.mod.common.api.spawning.context.SeafloorSpawningContext
import com.cobblemon.mod.common.api.spawning.position.SeafloorSpawnablePosition
import com.cobblemon.mod.common.util.Merger
import net.minecraft.world.level.block.Block
/**
* Base type for a spawning condition that applies to some kind of [SeafloorSpawningContext]. This
* can be extended for subclasses of [SeafloorSpawningContext].
* Base type for a spawning condition that applies to some kind of [SeafloorSpawnablePosition]. This
* can be extended for subclasses of [SeafloorSpawnablePosition].
*
* Borrowed the Grounded context code since it was unintentionally spawning Pokémon on the sea floor
* Borrowed the Grounded spawnable position code since it was unintentionally spawning Pokémon on the sea floor
* already. Seems to be working fine /shrug
*
* @author FrankTheFarmer
* @since May 22nd, 2024
*/
abstract class SeafloorTypeSpawningCondition<T : SeafloorSpawningContext> : AreaTypeSpawningCondition<T>() {
abstract class SeafloorTypeSpawningCondition<T : SeafloorSpawnablePosition> : AreaTypeSpawningCondition<T>() {
var neededBaseBlocks: MutableList<RegistryLikeCondition<Block>>? = null
override fun fits(ctx: T): Boolean {
return if (!super.fits(ctx)) {
override fun fits(spawnablePosition: T): Boolean {
return if (!super.fits(spawnablePosition)) {
false
} else if (minHeight != null && ctx.height < minHeight!!) {
} else if (minHeight != null && spawnablePosition.height < minHeight!!) {
false
} else if (maxHeight != null && ctx.height > maxHeight!!) {
} else if (maxHeight != null && spawnablePosition.height > maxHeight!!) {
false
} else if (neededBaseBlocks != null && neededBaseBlocks!!.none { it.fits(ctx.baseBlockHolder) }) {
} else if (neededBaseBlocks != null && neededBaseBlocks!!.none { it.fits(spawnablePosition.baseBlockHolder) }) {
false
} else {
true
@@ -54,13 +54,13 @@ abstract class SeafloorTypeSpawningCondition<T : SeafloorSpawningContext> : Area
}
/**
* A spawning condition for a [SeafloorSpawningContext].
* A spawning condition for a [SeafloorSpawnablePosition].
*
* @author FrankTheFarmer
* @since May 22nd, 2024
*/
open class SeafloorSpawningCondition : SeafloorTypeSpawningCondition<SeafloorSpawningContext>() {
override fun contextClass() = SeafloorSpawningContext::class.java
open class SeafloorSpawningCondition : SeafloorTypeSpawningCondition<SeafloorSpawnablePosition>() {
override fun spawnablePositionClass() = SeafloorSpawnablePosition::class.java
companion object {
const val NAME = "seafloor"
}
@@ -11,32 +11,29 @@ package com.cobblemon.mod.common.api.spawning.condition
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
import com.cobblemon.mod.common.api.spawning.MoonPhaseRange
import com.cobblemon.mod.common.api.spawning.TimeRange
import com.cobblemon.mod.common.api.spawning.context.FishingSpawningContext
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import com.cobblemon.mod.common.util.Merger
import com.cobblemon.mod.common.util.math.orMax
import com.cobblemon.mod.common.util.math.orMin
import com.mojang.datafixers.util.Either
import net.minecraft.resources.ResourceLocation
import net.minecraft.tags.TagKey
import net.minecraft.world.item.enchantment.EnchantmentHelper
import net.minecraft.world.item.enchantment.Enchantments
import net.minecraft.world.level.biome.Biome
import net.minecraft.world.level.levelgen.WorldgenRandom
import net.minecraft.world.level.levelgen.structure.Structure
/**
* The root of spawning conditions that can be applied to a spawning context. What type
* of spawning context it can be applied to is relevant for any subclasses.
* The root of spawning conditions that can be applied to a spawnable position. What type
* of spawnable position it can be applied to is relevant for any subclasses.
*
* @author Hiroku
* @since January 24th, 2022
*/
abstract class SpawningCondition<T : SpawningContext> {
abstract class SpawningCondition<T : SpawnablePosition> {
companion object {
val conditionTypes = mutableMapOf<String, Class<out SpawningCondition<*>>>()
fun getByName(name: String) = conditionTypes[name]
fun <T : SpawningContext, C : SpawningCondition<T>> register(name: String, clazz: Class<C>) {
fun <T : SpawnablePosition, C : SpawningCondition<T>> register(name: String, clazz: Class<C>) {
conditionTypes[name] = clazz
}
}
@@ -61,69 +58,72 @@ abstract class SpawningCondition<T : SpawningContext> {
var timeRange: TimeRange? = null
var structures: MutableList<Either<ResourceLocation, TagKey<Structure>>>? = null
var isSlimeChunk: Boolean? = null
var markers: MutableList<String>? = null
@Transient
var appendages = mutableListOf<AppendageCondition>()
abstract fun contextClass(): Class<out T>
fun contextMatches(ctx: SpawningContext) = contextClass().isAssignableFrom(ctx::class.java)
abstract fun spawnablePositionClass(): Class<out T>
fun spawnablePositionMatches(spawnablePosition: SpawnablePosition) = spawnablePositionClass().isAssignableFrom(spawnablePosition::class.java)
fun isSatisfiedBy(ctx: SpawningContext): Boolean {
return if (contextMatches(ctx)) {
fits(ctx as T)
fun isSatisfiedBy(spawnablePosition: SpawnablePosition): Boolean {
return if (spawnablePositionMatches(spawnablePosition)) {
fits(spawnablePosition as T)
} else {
false
}
}
protected open fun fits(ctx: T): Boolean {
if (ctx.position.x < minX.orMin() || ctx.position.x > maxX.orMax()) {
protected open fun fits(spawnablePosition: T): Boolean {
if (spawnablePosition.position.x < minX.orMin() || spawnablePosition.position.x > maxX.orMax()) {
return false
} else if (ctx.position.y < minY.orMin() || ctx.position.y > maxY.orMax()) {
} else if (spawnablePosition.position.y < minY.orMin() || spawnablePosition.position.y > maxY.orMax()) {
return false
} else if (ctx.position.z < minZ.orMin() || ctx.position.z > maxZ.orMax()) {
} else if (spawnablePosition.position.z < minZ.orMin() || spawnablePosition.position.z > maxZ.orMax()) {
return false
} else if (moonPhase != null && ctx.moonPhase !in moonPhase!!) {
} else if (moonPhase != null && spawnablePosition.moonPhase !in moonPhase!!) {
return false
} else if (ctx.light > maxLight.orMax() || ctx.light < minLight.orMin()) {
} else if (spawnablePosition.light > maxLight.orMax() || spawnablePosition.light < minLight.orMin()) {
return false
} else if (ctx.skyLight > maxSkyLight.orMax() || ctx.skyLight < minSkyLight.orMin()) {
} else if (spawnablePosition.skyLight > maxSkyLight.orMax() || spawnablePosition.skyLight < minSkyLight.orMin()) {
return false
} else if (timeRange != null && !timeRange!!.contains((ctx.world.dayTime() % 24000).toInt())) {
} else if (timeRange != null && !timeRange!!.contains((spawnablePosition.world.dayTime() % 24000).toInt())) {
return false
} else if (canSeeSky != null && canSeeSky != ctx.canSeeSky) {
} else if (canSeeSky != null && canSeeSky != spawnablePosition.canSeeSky) {
return false
} else if (isRaining != null && ctx.world.isRaining != isRaining!!) {
} else if (isRaining != null && spawnablePosition.world.isRaining != isRaining!!) {
return false
} else if (isThundering != null && ctx.world.isThundering != isThundering!!) {
} else if (isThundering != null && spawnablePosition.world.isThundering != isThundering!!) {
return false
} else if (dimensions != null && dimensions!!.isNotEmpty() && ctx.world.dimensionType().effectsLocation !in dimensions!!) {
} else if (dimensions != null && dimensions!!.isNotEmpty() && spawnablePosition.world.dimension().location() !in dimensions!!) {
return false
} else if (biomes != null && biomes!!.isNotEmpty() && biomes!!.none { condition -> condition.fits(ctx.biomeHolder) }) {
} else if (markers != null && markers!!.isNotEmpty() && markers!!.none { marker -> marker in spawnablePosition.markers }) {
return false
} else if (appendages.any { !it.fits(ctx) }) {
} else if (biomes != null && biomes!!.isNotEmpty() && biomes!!.none { condition -> condition.fits(spawnablePosition.biomeHolder) }) {
return false
} else if (appendages.any { !it.fits(spawnablePosition) }) {
return false
} else if (structures != null && structures!!.isNotEmpty() &&
structures!!.let { structures ->
val structureAccess = ctx.world.structureManager()
val cache = ctx.getStructureCache(ctx.position)
val structureAccess = spawnablePosition.world.structureManager()
val cache = spawnablePosition.getStructureCache(spawnablePosition.position)
return@let structures.none {
it.map({ cache.check(structureAccess, ctx.position, it) }, { cache.check(structureAccess, ctx.position, it) })
it.map({ cache.check(structureAccess, spawnablePosition.position, it) }, { cache.check(structureAccess, spawnablePosition.position, it) })
}
}
) {
return false
} else if (isSlimeChunk != null && isSlimeChunk != false) {
val isSlimeChunk = WorldgenRandom.seedSlimeChunk(ctx.position.x shr 4, ctx.position.z shr 4, ctx.world.seed, 987234911L).nextInt(10) == 0
val isSlimeChunk = WorldgenRandom.seedSlimeChunk(spawnablePosition.position.x shr 4, spawnablePosition.position.z shr 4, spawnablePosition.world.seed, 987234911L).nextInt(10) == 0
if (!isSlimeChunk) {
return false
}
/*val chunkX = ctx.position.x shr 4
val chunkZ = ctx.position.z shr 4
/*val chunkX = spawnablePosition.position.x shr 4
val chunkZ = spawnablePosition.position.z shr 4
val seed = (ctx.world.seed +
val seed = (spawnablePosition.world.seed +
(chunkX * chunkX * 4987142L) + (chunkX * 5947611L) +
(chunkZ * chunkZ * 4392871L) + (chunkZ * 389711L)) xor 987234911L
@@ -9,18 +9,18 @@
package com.cobblemon.mod.common.api.spawning.condition
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
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
* checks on whether a spawn can occur at a particular [SpawningContext]. This process
* checks on whether a spawn can occur at a particular [SpawnablePosition]. This process
* works by creating a [HashMap] keying from some property of a [SpawnDetail] and
* [SpawningContext] and mapping it to a list of spawns that were calculated ahead of
* [SpawnablePosition] and mapping it to a list of spawns that were calculated ahead of
* time as sharing that value. The requirement of implementations is only to get that
* key from both a [SpawnDetail] and a [SpawningContext].
* key from both a [SpawnDetail] and a [SpawnablePosition].
*
* When a precalculation has been registered with a [Spawner] by adding to [Spawner.precalculators],
* the precalculation result will need to be updated by running [Spawner.precalculate]. That
@@ -33,8 +33,8 @@ import net.minecraft.resources.ResourceLocation
interface SpawningPrecalculation<T : Any> {
/** Retrieves the precalculation keys for the given spawn detail. */
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?
/** Retrieves the precalculation key for the given spawnable position, if that key exists for this position. */
fun select(bucket: SpawnBucket, spawnablePosition: SpawnablePosition): T?
/**
* Generates a precalculation result for the list of [SpawnDetail]s and the subsequent precalculations.
@@ -74,23 +74,23 @@ interface SpawningPrecalculation<T : Any> {
object RootPrecalculation : SpawningPrecalculation<Any> {
val list = listOf(Unit)
override fun select(detail: SpawnDetail): List<Any> = list
override fun select(ctx: SpawningContext): Any = Unit
override fun select(bucket: SpawnBucket, spawnablePosition: SpawnablePosition): Any = Unit
}
/**
* A precalculation based on what context a spawn can be. This is a pretty sweet precalc.
* A precalculation based on what spawnable position type a spawn can be. This is a pretty sweet precalc.
*
* @author Hiroku
* @since February 14th, 2022
*/
object ContextPrecalculation : SpawningPrecalculation<Class<out SpawningContext>> {
override fun select(detail: SpawnDetail) = listOf(detail.context.clazz)
override fun select(ctx: SpawningContext) = ctx::class.java
object SpawnablePositionTypePrecalculation : SpawningPrecalculation<Class<out SpawnablePosition>> {
override fun select(detail: SpawnDetail) = listOf(detail.spawnablePositionType.clazz)
override fun select(bucket: SpawnBucket, spawnablePosition: SpawnablePosition) = spawnablePosition::class.java
}
object BucketPrecalculation : SpawningPrecalculation<SpawnBucket> {
override fun select(detail: SpawnDetail) = listOf(detail.bucket)
override fun select(ctx: SpawningContext) = ctx.cause.bucket
override fun select(bucket: SpawnBucket, spawnablePosition: SpawnablePosition) = bucket
}
/**
@@ -99,7 +99,7 @@ object BucketPrecalculation : SpawningPrecalculation<SpawnBucket> {
*/
object BiomePrecalculation : SpawningPrecalculation<ResourceLocation> {
override fun select(detail: SpawnDetail) = detail.validBiomes
override fun select(ctx: SpawningContext) = ctx.biomeHolder.unwrapKey().map { it.location() }.orElse(null)
override fun select(bucket: SpawnBucket, spawnablePosition: SpawnablePosition) = spawnablePosition.biomeHolder.unwrapKey().map { it.location() }.orElse(null)
}
/**
@@ -113,8 +113,8 @@ object BiomePrecalculation : SpawningPrecalculation<ResourceLocation> {
sealed class PrecalculationResult<T : Any>(
val calculation: SpawningPrecalculation<*>
) {
/** Gets the list of spawn details that fit this context. */
abstract fun retrieve(ctx: SpawningContext): List<SpawnDetail>
/** Gets the list of spawn details that fit this spawnable position. */
abstract fun retrieve(bucket: SpawnBucket, spawnablePosition: SpawnablePosition): List<SpawnDetail>
}
/**
@@ -127,7 +127,7 @@ class NestedPrecalculationResult<T : Any>(
calculation: SpawningPrecalculation<T>,
val mapping: Map<T, PrecalculationResult<*>> = mutableMapOf()
) : PrecalculationResult<T>(calculation) {
override fun retrieve(ctx: SpawningContext) = mapping[calculation.select(ctx)]?.retrieve(ctx) ?: emptyList()
override fun retrieve(bucket: SpawnBucket, spawnablePosition: SpawnablePosition) = mapping[calculation.select(bucket, spawnablePosition)]?.retrieve(bucket, spawnablePosition) ?: emptyList()
}
/**
@@ -141,5 +141,5 @@ class FinalPrecalculationResult<T : Any>(
calculation: SpawningPrecalculation<*>,
val mapping: Map<T, List<SpawnDetail>>
) : PrecalculationResult<T>(calculation) {
override fun retrieve(ctx: SpawningContext) = mapping[calculation.select(ctx)] ?: emptyList()
override fun retrieve(bucket: SpawnBucket, spawnablePosition: SpawnablePosition) = mapping[calculation.select(bucket, spawnablePosition)] ?: emptyList()
}
@@ -9,37 +9,37 @@
package com.cobblemon.mod.common.api.spawning.condition
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
import com.cobblemon.mod.common.api.spawning.context.SubmergedSpawningContext
import com.cobblemon.mod.common.api.spawning.position.SubmergedSpawnablePosition
import com.cobblemon.mod.common.util.Merger
import net.minecraft.world.level.material.Fluid
/**
* Base type for a spawning condition that applies to some kind of [SubmergedSpawningContext]. This
* can be extended for subclasses of [SubmergedSpawningContext].
* Base type for a spawning condition that applies to some kind of [SubmergedSpawnablePosition]. This
* can be extended for subclasses of [SubmergedSpawnablePosition].
*
* @author Hiroku
* @since February 7th, 2022
*/
abstract class SubmergedTypeSpawningCondition<T : SubmergedSpawningContext> : AreaTypeSpawningCondition<T>() {
abstract class SubmergedTypeSpawningCondition<T : SubmergedSpawnablePosition> : AreaTypeSpawningCondition<T>() {
var minDepth: Int? = null
var maxDepth: Int? = null
var fluidIsSource: Boolean? = null
var fluid: RegistryLikeCondition<Fluid>? = null
override fun fits(ctx: T): Boolean {
return if (!super.fits(ctx)) {
override fun fits(spawnablePosition: T): Boolean {
return if (!super.fits(spawnablePosition)) {
false
} else if (minHeight != null && ctx.height < minHeight!!) {
} else if (minHeight != null && spawnablePosition.height < minHeight!!) {
return false
} else if (maxHeight != null && ctx.height > maxHeight!!) {
} else if (maxHeight != null && spawnablePosition.height > maxHeight!!) {
return false
} else if (minDepth != null && ctx.depth < minDepth!!) {
} else if (minDepth != null && spawnablePosition.depth < minDepth!!) {
false
} else if (maxDepth != null && ctx.depth > maxDepth!!) {
} else if (maxDepth != null && spawnablePosition.depth > maxDepth!!) {
false
} else if (fluidIsSource != null && ctx.fluid.isSource != fluidIsSource!!) {
} else if (fluidIsSource != null && spawnablePosition.fluid.isSource != fluidIsSource!!) {
false
} else !(ctx.fluid.isEmpty || (fluid != null && !fluid!!.fits(ctx.fluid.type, ctx.fluidRegistry)))
} else !(spawnablePosition.fluid.isEmpty || (fluid != null && !fluid!!.fits(spawnablePosition.fluid.type, spawnablePosition.fluidRegistry)))
}
override fun copyFrom(other: SpawningCondition<*>, merger: Merger) {
@@ -54,13 +54,13 @@ abstract class SubmergedTypeSpawningCondition<T : SubmergedSpawningContext> : Ar
}
/**
* A spawning condition for an [SubmergedSpawningContext].
* A spawning condition for an [SubmergedSpawnablePosition].
*
* @author Hiroku
* @since February 7th, 2022
*/
open class SubmergedSpawningCondition : SubmergedTypeSpawningCondition<SubmergedSpawningContext>() {
override fun contextClass() = SubmergedSpawningContext::class.java
open class SubmergedSpawningCondition : SubmergedTypeSpawningCondition<SubmergedSpawnablePosition>() {
override fun spawnablePositionClass() = SubmergedSpawnablePosition::class.java
companion object {
const val NAME = "submerged"
}
@@ -9,30 +9,30 @@
package com.cobblemon.mod.common.api.spawning.condition
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
import com.cobblemon.mod.common.api.spawning.context.SurfaceSpawningContext
import com.cobblemon.mod.common.api.spawning.position.SurfaceSpawnablePosition
import com.cobblemon.mod.common.util.Merger
import net.minecraft.world.level.material.Fluid
/**
* Base type for a spawning condition that applies to some kind of [SurfaceSpawningContext]. This
* can be extended for subclasses of [SurfaceSpawningContext].
* Base type for a spawning condition that applies to some kind of [SurfaceSpawnablePosition]. This
* can be extended for subclasses of [SurfaceSpawnablePosition].
*
* @author Hiroku
* @since December 15th, 2022
*/
abstract class SurfaceTypeSpawningCondition<T : SurfaceSpawningContext> : AreaTypeSpawningCondition<T>() {
abstract class SurfaceTypeSpawningCondition<T : SurfaceSpawnablePosition> : AreaTypeSpawningCondition<T>() {
var minDepth: Int? = null
var maxDepth: Int? = null
var fluid: RegistryLikeCondition<Fluid>? = null
override fun fits(ctx: T): Boolean {
return if (!super.fits(ctx)) {
override fun fits(spawnablePosition: T): Boolean {
return if (!super.fits(spawnablePosition)) {
false
} else if (minDepth != null && ctx.depth < minDepth!!) {
} else if (minDepth != null && spawnablePosition.depth < minDepth!!) {
false
} else if (maxDepth != null && ctx.depth > maxDepth!!) {
} else if (maxDepth != null && spawnablePosition.depth > maxDepth!!) {
false
} else !(ctx.baseBlock.fluidState.isEmpty || (fluid != null && !fluid!!.fits(ctx.baseBlock.fluidState.type, ctx.fluidRegistry)))
} else !(spawnablePosition.baseBlock.fluidState.isEmpty || (fluid != null && !fluid!!.fits(spawnablePosition.baseBlock.fluidState.type, spawnablePosition.fluidRegistry)))
}
override fun copyFrom(other: SpawningCondition<*>, merger: Merger) {
@@ -46,13 +46,13 @@ abstract class SurfaceTypeSpawningCondition<T : SurfaceSpawningContext> : AreaTy
}
/**
* A spawning condition for a [SurfaceSpawningContext].
* A spawning condition for a [SurfaceSpawnablePosition].
*
* @author Hiroku
* @since December 15th, 2022
*/
open class SurfaceSpawningCondition : SurfaceTypeSpawningCondition<SurfaceSpawningContext>() {
override fun contextClass() = SurfaceSpawningContext::class.java
open class SurfaceSpawningCondition : SurfaceTypeSpawningCondition<SurfaceSpawnablePosition>() {
override fun spawnablePositionClass() = SurfaceSpawnablePosition::class.java
companion object {
const val NAME = "surface"
}

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