forked from mirrors/cobblemon
Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
584983e616 | ||
|
|
e86559b5d4 | ||
|
|
f83bc8c58f | ||
|
|
278e9afb1a | ||
|
|
bb2f8793f4 | ||
|
|
31697b3c73 | ||
|
|
45943a884a | ||
|
|
3f6b8b6de8 | ||
|
|
696df0e0e5 | ||
|
|
d57e6d058f | ||
|
|
a87929019d | ||
|
|
84e6931b88 | ||
|
|
84c29fdf62 | ||
|
|
881ad52f36 | ||
|
|
377dc44d7e |
@@ -36,11 +36,9 @@ common/src/main/resources/assets/cobblemon/showdown
|
||||
# Generated files
|
||||
*/generated/resources/*
|
||||
/fabric/src/generated/resources/cobblemon-common.accesswidener
|
||||
/fabric/src/main/generated/*
|
||||
/.ignored/
|
||||
common/.fabric
|
||||
.kotlin/
|
||||
|
||||
# MacOS
|
||||
.DS_Store
|
||||
/common/config/*
|
||||
|
||||
+7
-3
@@ -1,4 +1,4 @@
|
||||
image: amazoncorretto:21
|
||||
image: amazoncorretto:25
|
||||
|
||||
before_script:
|
||||
- export GRADLE_USER_HOME=`pwd`/.gradle
|
||||
@@ -16,6 +16,7 @@ check_assets_cache:
|
||||
stage: preprocessing
|
||||
script:
|
||||
- echo "Checking if cached hash matches current hash"
|
||||
- yum install -y findutils
|
||||
|
||||
# Calculate the current hash
|
||||
- find common/src/main/resources/assets common/src/main/resources/data -type f -exec sha256sum {} + | sort -k 2 | sha256sum > current_hash.txt
|
||||
@@ -148,6 +149,7 @@ build:
|
||||
dependencies:
|
||||
- replace_resources
|
||||
script:
|
||||
- yum install -y findutils
|
||||
- export GRADLE_OPTS="-Xmx4G -Xms4G"
|
||||
- chmod +x ./gradlew
|
||||
- ./gradlew build
|
||||
@@ -163,6 +165,7 @@ publish:
|
||||
rules:
|
||||
- if: '$CI_PROJECT_PATH == "cable-mc/cobblemon" && $CI_COMMIT_BRANCH == "main"'
|
||||
script:
|
||||
- yum install -y findutils
|
||||
- export GRADLE_OPTS="-Xmx4G -Xms4G"
|
||||
- chmod +x ./gradlew
|
||||
- ./gradlew publish
|
||||
@@ -176,9 +179,10 @@ deploy_artifacts:
|
||||
dependencies:
|
||||
- build
|
||||
script:
|
||||
- yum install -y findutils
|
||||
- echo "Collecting artifacts..."
|
||||
- find neoforge/build/libs/ -type f -name "*.jar" | grep -vE "dev-shadow|sources|javadoc" | xargs -I {} mv {} ./
|
||||
- find fabric/build/libs/ -type f -name "*.jar" | grep -vE "dev-shadow|sources|javadoc" | xargs -I {} mv {} ./
|
||||
- find neoforge/build/libs/ -type f -name "*.jar" | grep -vE "dev-slim|sources|javadoc" | xargs -I {} mv {} ./
|
||||
- find fabric/build/libs/ -type f -name "*.jar" | grep -vE "dev-slim|sources|javadoc" | xargs -I {} mv {} ./
|
||||
- for f in *.jar; do mv "$f" "$(echo "$f" | sed s/+/b$CI_PIPELINE_IID+/)"; done
|
||||
artifacts:
|
||||
paths:
|
||||
|
||||
+23
-342
@@ -1,385 +1,66 @@
|
||||
# Changelog
|
||||
## [1.8.0 (MONTH Xth, 2026)](#1-8-0)
|
||||
## [1.7.4 (MONTH Xth, 2026)](#1-7-4)
|
||||
|
||||
### Additions
|
||||
- Added config options to award experience to fainted Pokémon for opponents they helped defeat (`awardExperienceToFaintedPokemon`) and to still award experience for defeated enemies even after battle loss/forfeit (`awardExperienceOnBattleLoss`)
|
||||
- Party Overlay Exp Gained Animation will now display the amount of EXP the Pokémon gained
|
||||
- Added a toast to notify players of how they can scroll through their party. Did you know you can hold R and scroll instead of using arrow keys??!
|
||||
- Added a new layer property that makes a layer scroll in a direction. "scrolling": {"speedU": 0.1, "speedV": 0.1}
|
||||
- Added new layer property that makes a layer scroll in a direction. "scrolling": {"speedU": 0.1, "speedV": 0.1}
|
||||
- Added missing crops to Botany Pots integration
|
||||
- Added a way to obtain Porygon by inserting the Upgrade or Dubious Disc into a data monitor
|
||||
- Added a new `cobblemon:structure`, which is a feature without any restrictions allowing the Builders to place certain structures in much more specific manner.
|
||||
- Added Configs for Infinite Use TMs and Unlocking all TMs
|
||||
- Added Type Gem blocks
|
||||
- Added Type Gem Clusters
|
||||
- Added TMs
|
||||
- Added TM Machine
|
||||
- Added Deepslate Core Block
|
||||
- Added /givetm Command
|
||||
- Added advancement triggers for learning TMs: `cobblemon:has_learn_specific_tm` (per-TM), `cobblemon:has_learn_all_tm` (all TMs learned), and `cobblemon:tms_learned` (count-based), backed by a new `totalTMLearnedCount` on player advancement data.
|
||||
- Added `cobblemon:catch_alpha_pokemon` advancement trigger and `totalAlphaCaptureCount` tracking for capturing Alpha Pokémon.
|
||||
- Added Move Dex to Pokédex
|
||||
- Added the Habitat Block, a spawner block for servers and adventure maps that controls spawning in an area.
|
||||
- Added Disk Rack for storing disks and being an audio sequencer for Noteblocks
|
||||
- Added intrinsic scaling to all mons (+-5%). Some rendering cases, such as shoulder mounting, revert to 1.0 scaling to preserve animation accuracy.
|
||||
- Added scaling to "baby" Pokémon (smaller (-20%) at level 1 → normally sized at level 10)
|
||||
- Added conditional seats for riding. Seats can be gated by molang such as "is_alpha".
|
||||
- Added Alpha Pokémon
|
||||
- Added alpha scaling (alphas are larger than their normal counterparts)
|
||||
- Alphas will always lead herds and will spawn in herds
|
||||
- Alphas spawn with two random TM moves from their learnset
|
||||
- Alpha Pokémon will always defend themselves from players that attack them
|
||||
- Added alpha level matching and stat boost (based on level)
|
||||
- Added pitch-down and reverb to alpha cries
|
||||
- Added alpha Pokémon bait effect
|
||||
- Added alpha eye rendering including eye overlay, bloom, eye trail, and particles.
|
||||
- Added cobweb block slowness immunity for spider Pokémon
|
||||
- Added 49 new habitat structures. 34 as typical Minecraft structures and 15 as structures that get placed as biome features to allow for more natural placement in generation. Structures placed as biome features will not be able to be located with the `/locate structure` command.
|
||||
- Vanilla village house template pools have been adjusted to account for the new abandoned village structure habitat. Weights have changed within the JSON file for every piece to ensure too many habitats don't generate in a single village.
|
||||
- Added 10 new ruin structures.
|
||||
- rooted_arch_ruins & crumbling_arch_ruins have been transferred over to biome features, allowing for better placement in generation.
|
||||
- All ruin structures that did not generate with a gimmighoul/gilded chest before will now generate with one.
|
||||
- All ruin structures gilded chest loot tables have been updated to include a guaranteed TM not learned naturally by any Pokémon through their level-up moveset. Each ruin gets its own specific TM, so you can now go hunting ruins to complete your move dex!
|
||||
- All fossil structures have been transferred over to biome features, allowing for better placement in generation.
|
||||
- The prehistoric_underwater_fissure & prehistoric_submerged_impact fossil structures now use the biome tag `#cobblemon:is_temperate_ocean`.
|
||||
- A new Biome tag called `#cobblemon:is_stony_beach` has been added.
|
||||
- Gimmighoul towers now generate at ground level rather than sinking one block into the ground.
|
||||
- 1 New shipwreck cove structure called the "magma_shipwreck_cove" has been added.
|
||||
- Shipwreck coves now generate slightly more frequently.
|
||||
- Added equipment loot tables for shipwreck cove enemies.
|
||||
- Maps from abandoned fishing boats leading to shipwreck coves now will skip explored chunks, allowing the player to find more shipwreck coves easier.
|
||||
- The lush shipwreck cove's phantom mob spawner has been replaced with breezes.
|
||||
- The lush shipwreck cove structure itself has been slightly cleaned up to be less noisy with the blocks it is built out of.
|
||||
- All shipwreck coves' spawners have been adjusted to give compatible mobs enchanted iron or diamond armour and weapons while in its ominous state. The armour given to the mobs will also use the automaton trim. We upped the difficulty because it was too easy now that your Pokémon can fight for you.
|
||||
- One TM of the elemental hyper beams has been added as guaranteed loot to the main treasure chest in every shipwreck cove. (Magma cove gets blast burn, lush cove gets frenzy plant, and submerged cove gets hydro cannon)
|
||||
- Added 7 new advancements
|
||||
- Pressing the inventory key now closes the Pokémon interact wheel GUI
|
||||
- Pokémon cries now play when clicking Pokémon in the summary screen.
|
||||
- Pressing the Summary key while either the starter selection or summary screen are open now closes those screens
|
||||
|
||||
### New rideable Pokémon
|
||||
- Drampa
|
||||
- Archeops
|
||||
- Skarmory
|
||||
- Crobat
|
||||
- Goodra
|
||||
- Hisuian Goodra
|
||||
- Milotic
|
||||
|
||||
### Pokémon Added
|
||||
- Wurmple
|
||||
- Silcoon
|
||||
- Beautifly
|
||||
- Cascoon
|
||||
- Dustox
|
||||
- Skitty
|
||||
- Delcatty
|
||||
|
||||
- Seviper
|
||||
- Zangoose
|
||||
- Cherubi
|
||||
- Cherrim
|
||||
- Stunky
|
||||
- Skuntank
|
||||
|
||||
- Audino
|
||||
- Pawniard
|
||||
- Bisharp
|
||||
- Kingambit
|
||||
|
||||
- Pancham (+ Cosmetic with Black Glasses)
|
||||
- Pangoro (+ Cosmetic with Black Glasses)
|
||||
|
||||
- Rockruff
|
||||
- Lycanroc
|
||||
|
||||
- Rolycoly
|
||||
- Carkol
|
||||
- Coalossal
|
||||
|
||||
- Snom
|
||||
- Frosmoth
|
||||
|
||||
- Duraludon
|
||||
- Archaludon
|
||||
|
||||
- Applin
|
||||
- Flapple
|
||||
- Appletun
|
||||
- Dipplin
|
||||
- Hydrapple
|
||||
|
||||
- Nymble
|
||||
- Lokix
|
||||
|
||||
#### Regional Forms
|
||||
- Sandshrew (Alolan)
|
||||
- Sandslash (Alolan)
|
||||
- Avalugg (Hisuian)
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
- Goomy
|
||||
- Sliggoo
|
||||
- Goodra
|
||||
- Porygon
|
||||
- Porygon2
|
||||
- Porygon-Z
|
||||
- Zubat
|
||||
- Golbat
|
||||
- Crobat
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
|
||||
- Sandshrew
|
||||
- Sandslash
|
||||
- Nidoking
|
||||
- Zubat
|
||||
- Golbat
|
||||
- Crobat
|
||||
- Porygon
|
||||
- Porygon2
|
||||
- Porygon-Z
|
||||
|
||||
- Skarmory
|
||||
- Jynx
|
||||
- Popplio
|
||||
- Brionne
|
||||
- Primarina
|
||||
- Fletchling
|
||||
- Fletchinder
|
||||
- Talonflame
|
||||
|
||||
- Sableye
|
||||
- Mawile
|
||||
|
||||
- Goomy
|
||||
- Sliggoo
|
||||
- Goodra
|
||||
|
||||
- Nacli
|
||||
- Naclstack
|
||||
- Garganacl
|
||||
|
||||
#### Model changes to the regional bias resource pack:
|
||||
|
||||
- Added Mime Jr. (Galar Bias)
|
||||
- Added Bergmite (Hisui Bias)
|
||||
- Changed models for every existing regional bias
|
||||
|
||||
### Animation updates for the following Pokémon
|
||||
- Skarmory
|
||||
- Skitty
|
||||
- Flygon
|
||||
- Shellos
|
||||
- Riolu
|
||||
- Lucario
|
||||
- Purrloin
|
||||
- Liepard
|
||||
- Joltik
|
||||
- Galvantula
|
||||
- Nidoking
|
||||
- Fletchling
|
||||
- Fletchinder
|
||||
- Talonflame
|
||||
- Archeops
|
||||
- Drampa
|
||||
- Sewaddle
|
||||
- Swadloon
|
||||
- Leavanny
|
||||
- Goomy
|
||||
- Sliggoo
|
||||
- Goodra
|
||||
- Shedinja
|
||||
- Skwovet
|
||||
- Greedent
|
||||
|
||||
#### Added sounds to the following moves
|
||||
- Absorb
|
||||
- Aurora Beam
|
||||
- Double Team
|
||||
- Draco Meteor
|
||||
- Fire Punch
|
||||
- Fire Spin
|
||||
- Flame Charge
|
||||
- Flame Wheel
|
||||
- Giga Drain
|
||||
- Ice Punch
|
||||
- Leech Life
|
||||
- Magical Leaf
|
||||
- Mega Drain
|
||||
- Minimize
|
||||
- Poison Gas
|
||||
- Rock Throw
|
||||
- Scary Face
|
||||
- Seed bomb
|
||||
- Smokescreen
|
||||
- String Shot
|
||||
- Tail Whip
|
||||
|
||||
### Changes
|
||||
- Stat increase and decrease particles have been changed, with the addition of alpha boost particles.
|
||||
- Dragonite's mailbag cosmetic can now also be obtained with a chest in the cosmetic slot
|
||||
|
||||
### Fixes
|
||||
- Adjusted Croagunk's walkspeed
|
||||
- Fixed Blitzle's base scale being `1` rather than the intended `0.8`
|
||||
- Fixed Magnezone's emissive layer for the shiny having the wrong name, thus displaying wrongly
|
||||
- Fixed Litleo not blinking
|
||||
- Fixed Garchomp T-posing when sleeping while out of battle.
|
||||
- Sharp Beak can now be crafted
|
||||
- Metal Alloy can now be crafted
|
||||
- Ability Capsules can now be brewed
|
||||
- Using an Ability Capsule will now return an Empty Bottle
|
||||
- The following items can now be obtained by brushing the following Pokémon:
|
||||
- Pink Wool - Wigglytuff
|
||||
- White Wool - Swablu, Altaria
|
||||
- Shed Shell - Ekans, Arbok, Dratini, Dragonair, Dunsparce, Treecko, Grovyle, Sceptile, Seviper, Scraggy, Scrafty, Helioptile, Heliolisk, Salandit, Salazzle, Sobble, Drizzile, Inteleon, Silicoblra, Sandaconda, Toxel, Toxtricity, Orthworm, Dudunsparce
|
||||
- Phantom Membrane - Dreepy, Drakloak, Dragapult
|
||||
- The following items can now be obtained by evolving the following Pokémon into any of their evolutions:
|
||||
- Turtle Scute - Squirtle, Wartortle, Turtwig, Grotle, Tirtouga, Chewtle
|
||||
- Shed Shell - Metapod, Kakuna, Ekans, Paras, Venonat, Krabby, Scyther, Kabuto, Dratini, Dragonair, Ledyba, Spinarak, Yanma, Pineco, Dunsparce, GLigar, Pupitar, Treecko, Grovyle, Silcoon, Cascoon, Surskit, Nincada, Trapinch, Vibrava, Corphish, Anorith, Bagon, Shelgon, Kricketot, Burmy, Combee, Skorupi, Swadloon, Whirlipede, Dwebble, Scraggy, Karrablast, Joltik, Larvesta, Spewpa, Clauncher, Helioptile, Charjabug, Crabrawler, Cutiefly, Dewpider, Salandit, Wimpod, Poipole, Sobble, Drizzile, Dottler, Silicobra, Toxel, Sizzlipede, Snom, Tarountula, Nymble, Rellor
|
||||
- Saccharine Leaves now drop Tart, Sweet, or Syrupy Apples, depending on their honey coating stage, instead of vanilla Apples
|
||||
- Fixed the height of the Tumblestone Bud items when held in hand, placed on head, viewed in a GUI, and placed in an Item Frame
|
||||
- Refactored all advancements, removing several deemed unnecessary. Due to this refactor, all previously obtained advancements will be reset besides the root (for picking a starter Pokémon). We are sorry for the inconvience, but it makes the tab cleaner and simplifies future advancements.
|
||||
- Restructured Botany Pots integration folder structure
|
||||
- Decrease the default pastured mon wander radius to 32.
|
||||
- Factor in the weight of Pokémon when calculating pushing forces between hitboxes.
|
||||
- Decrease default pastured mon wander radius to 32.
|
||||
- Factor in the weight of pokemon when calculating pushing forces between hitboxes.
|
||||
- Remade the Starter Selection Screen with new assets
|
||||
- Refactored berry trees to be less impactful on TPS (more performant)
|
||||
- Changed the bait effects of the following items: (Vanilla) Sweet & Glow Berries, Golden & Enchanted Golden Apples (Cobblemon) Custap, Eggant, Hopo & Micle Berries, Sweet Hearts
|
||||
- Wild Pokémon now reliably have at least one offensive move if they can have offensive moves at that level.
|
||||
- Data Monitor can accept Disks (TMs, Music Disks, Upgrade, Dubious Disk, etc.) to change what's being displayed on the screen
|
||||
- Rider positioning is now client-driven (Remove poseOffsets and offset per seat/pose) in favour of sending real-time passenger position.
|
||||
- Cleaned up seat data. Removed all now unused fields from seats in all species files. Also made locator seat names explicit in the species files (however, this doesn't break the legacy format)
|
||||
- Marks can now provide aspects.
|
||||
- Added new shiny and Alpha chance configs
|
||||
- Apricorns now make a new sound when harvested
|
||||
- Lowered the volume of harvesting berries
|
||||
- Added alternate versions of the basic PC Wallpapers based on the original design of Cobblemon's PC, before public release
|
||||
- Improved compatibility with various mods
|
||||
- Farmer's Delight's cutting board can now be used to strip Apricorn and Saccharine's logs, or salvage their planks from various blocks. It can also separate their boats from chests
|
||||
- Farmer's Delight's cutting board can be used to get two white dye from Pep-Up Flowers and two magenta dye from Medicinal Leeks
|
||||
- Farmer's Delight's cutting board can separate Tumblestone Blocks back into Tumblestones
|
||||
- Farmer's Delight's cutting board can salvage Type Gems from their Gem Blocks
|
||||
- Farmer's Delight's Onions, Tomatoes, and Cabbages can be used to cook Open-Faced Sandwiches. Nature's Spirit's Olives also can be used
|
||||
- Farmer's Delight's cutting board can be used on Hearty Grains to obtain rice and straw, similarly to Farmer's Delight's Rice Panicles
|
||||
- Farmer's Delight's Apple Pies and Apple Ciders can now be made using Applin Apples, alongside the Vanilla counterpart
|
||||
- Amendments allows for cooking Leek and Potato Stew in a Cauldron
|
||||
- Any mods that utilise Moonlight's Soft Fluid system can store Leek and Potato Stew, Medicinal Brew, Antidote, Awakening, Burn Heal, Ice Heal, Paralyze Heal, Full Heal, Potion, Super Potion, Hyper Potion, Max Potion, Full Restore, Ability Capsules, Moomoo Milk, and Berry Juice in liquid form (such as Suplementaries' Jar or Goblet, or Cauldrons while using Amendments)
|
||||
- Supplementaries' Hourglass can now use Bright Powder, Quick Powder, Metal Powder, Heal Powder, Silver Powder, and Remedy
|
||||
- Berry Trees are now compatible with the Planter properly
|
||||
- Saccharine Way Signs (added by Supplementaries automagically) now use a premade texture to prevent odd visual issues
|
||||
- Supplementaries' Jar can now store various Cobblemon cookies, candies, and similar items
|
||||
- Some of Supplementaries' items have been added to the `#cobblemon:held/container_held_items` item tag, including sacks, safes, and lunch baskets
|
||||
- Experience Nuggets can be used in place of Sculk for making the EXP Candies if using Create
|
||||
- Rage Candy Bar has a Create Mixing recipe
|
||||
- All Cobblemon ores can now be crushed in Create's Crushing Wheels
|
||||
- All Gem and Tumblestone Clusters can be crushed for automatic, low return, gems
|
||||
- Hearty Grains can be milled like Farmer's Delight Rice Panicles if both Farmer's Delight and Create are installed
|
||||
- Big Roots and Revival Herbs can be milled to their respective powders
|
||||
- Pep-Up Flowers, Medicinal Leeks, and all 70 berries can be milled in Create's Millstone for additional dye drops
|
||||
- Auspicious Armor and Upgrades can be Haunted using Create's crafting systems
|
||||
- Applin Apples can be used to make Honeyed Apples in Create
|
||||
- Golden Apples can now be crafted using the Applin Apples
|
||||
- Prismarine Crystals and Amethyst Shards can now be used to craft Pokedexes
|
||||
- Updated Pokedex Screens item tag to support tagged variants of Redstone and Glowstone Dust
|
||||
- Sounds for interacting with various Cobblemon blocks now play from the center of the block, rather than the corner
|
||||
- The `/pc` command no longer plays PC activation sounds
|
||||
- Lowered the volume of Blitzle and Zebstrika's cry
|
||||
- Fixed Raichu (male) and Alolan Raichu (both genders) not displaying the correct Partner Cap when Pewter Crunchies are in the cosmetic slot.
|
||||
- Regional Foods will now prioritize being eaten instead of used for healing Pokémon, shift clicking will use it as healing
|
||||
|
||||
### Fixes
|
||||
- Fixed Croagunk's walkspeed
|
||||
- Fixed Blitzle's base scale being `1` rather than the intended `0.8`
|
||||
- Fixed Magnezone's emissive layer for the shiny having the wrong name, thus displaying wrongly
|
||||
- Fixed Litleo not blinking
|
||||
- Fixed Pokédex layout for genderless variations
|
||||
- Fixed odd stacking behaviour with the poke_bait item.
|
||||
- Fixes https://gitlab.com/cable-mc/cobblemon/-/issues/1943
|
||||
- Fix occasional crash on retrieving revived fossils
|
||||
- Fixed a compatibility issue with World Game Rules which caused some log spam in specific cases.
|
||||
- Fixed improper validation of Pokémon when performing a trade.
|
||||
- Fixed an issue where particle like beam can disappear when you don't see the beginning of the beam, or you look away
|
||||
- Fixed Bedrock particle materials (alpha/opaque/blend/add) sharing one render batch, which caused incorrect culling on mixed batches; each material now batches and draws with its own blend and cull state, and the alpha material renders as a true cutout
|
||||
- Fixed an occasional crash on retrieving revived fossils
|
||||
- Fixed brushing not working on Neoforge
|
||||
- Fixed braking not working for submarines (whoops).
|
||||
- Fixed strafing not having the same friction as forward movement (funny whoops).
|
||||
- Fixed submarine's surface-water animations not playing when supposed to.
|
||||
- Fixed submarine camera freaking out when looking up or down on the surface.
|
||||
- Fixed pastured mons despawning and running away.
|
||||
- Fixed Apricorn trees crashing when other mods bonemeal it
|
||||
- Fixed the issue that caused Hover Behaviour rides without a ground style to be rendered useless upon touching the ground on a server.
|
||||
- Removed the "inAir" penalty for block destruction speed when on a hover mount.
|
||||
- Fixed horizontal and vertical collisions with hover mounts so they no longer accumulate or retain momentum
|
||||
- Fixed NeoForge brewing stand unexpectedly crashing users when shift clicking items within its menu
|
||||
- Fixed NPCs switching Pokémon very often during battles
|
||||
- Fixed issue where particle like beam can disappear when you don't see the beginning of the beam or you look away
|
||||
- Fixes https://gitlab.com/cable-mc/cobblemon/-/issues/1943
|
||||
- Fix occasional crash on retrieving revived fossils
|
||||
- Fix brushing not working on Neoforge
|
||||
- [Various Submarine Ride Fixes](https://gitlab.com/cable-mc/cobblemon/-/merge_requests/2157)
|
||||
- Fix Pastured mons despawning and running away.
|
||||
- Fix Apricorn trees crashing when other mods bonemeal it
|
||||
- [Various UFO Ride Improvements](https://gitlab.com/cable-mc/cobblemon/-/merge_requests/2156)
|
||||
- Fixed NeoForge brewing stand unexpectedly crashing users when shift clicking items within it's menu
|
||||
- Fixed NPCs switching pokemon very often during battles
|
||||
- Fixed Campfire pot causing crashes under certain circumstances
|
||||
- Fixed Type Gems not being consumed upon use
|
||||
- Fixed Ancient Pokéball's to their respective modifiers
|
||||
- Fixed a Server warning when recalling Pokémon
|
||||
- Fixed Ancient Pokeball's to their respective modifiers
|
||||
- Fixed a Server warning when recalling Pokemon
|
||||
- Fixed sliding particles incorrectly handling block collision
|
||||
- Fixed Full Heal not curing status conditions in battle
|
||||
- Fixed a rare issue with battles locking up when you are forced to switch, with the switch menu appearing instantly.
|
||||
- Fixed the combined effects of Pledge moves having broken Showdown message handling and localisation
|
||||
- Fixed rare Pokémon being far too likely to spawn multiple times in a single spawn cycle. The dev told me that the exact bug is too complicated to explain.
|
||||
- Resolved the niche issue where Structures would spawn in an incorrect location, creating very funky world gen.
|
||||
- Fixed Galarian Ponyta missing its cry.
|
||||
- Fixed various log warnings caused by redundant files and sound events.
|
||||
- Traded Pokémon will now retain the original friendship level when traded back to its OT
|
||||
- Clusters now display correctly on maps
|
||||
- Fixed removing mulch from berry trees with a shovel not working.
|
||||
- Fixed collecting honey from Saccharine Leaf blocks deleting Honey Bottles when the inventory was full
|
||||
- Fixed Stripped Saccharine Wood recipe being missing
|
||||
- Fixed CancelableSoundInstance causing lag by attempting to create sounds every tick when out of range of hearing
|
||||
- Fixed Stat Reducing Aprijuice not being possible to apply on a max out Pokémon, and the possibility of going into negatives
|
||||
- Fixed Exploit where you could take out the bait or drop your Pokérod with bait to avoid consuming bait, now the bobber will just disappear if you do so
|
||||
- Fixed Apricorn and Saccharine boats incorrectly using chest boat models
|
||||
- Fixed wild and trainer battle AI refusing to select moves with the `adjacentAlly` target type, even when it's their only option
|
||||
- Fixed Guilded chests being more accessible than intended
|
||||
- Fixed fished up Pokémon not being added as "seen" to the Pokedex
|
||||
- Fixed surprised Gimmighoul encounters not being added as "seen" to the Pokedex
|
||||
|
||||
### Developer
|
||||
- Added `PokeSnackSpawnerFactory` which allows influence registration on PokeSnack encounters
|
||||
- Added `FishingSpawnerFactory` which allows influence registration on fishing encounters
|
||||
- Added `BattleFleeAttemptEvent` fired from `PokemonBattle.checkFleeAttempt`, allowing developers to intercept and control flee attempts
|
||||
- Tweaked the spawning selector interface to take a bucket function rather than a bucket directly.
|
||||
- Added a new `cobblemon:height_range` processor type to allow developers to restrict structure-spawning ranges.
|
||||
- Separated all the functions of MoLangFunctions.kt into their own files.
|
||||
- Spawn buckets and their base weights are now provided by the spawner, with different base weights for world, fishing, snack, and habitat spawn buckets.
|
||||
- Removed "SpawnBucket" class in favour of just storing maps of bucket names to weights.
|
||||
|
||||
### Molang & Datapacks
|
||||
- Added `moveset_builders` datapack folder for different styles of movesets.
|
||||
- Added `party_pools` datapack folder for defining groups of Pokémon for complex NPC party definitions.
|
||||
- Added `party_compositions` datapack folder for arranging parties on NPCs that rely on party pools.
|
||||
- Added `composed_pool` NPC party provider type which combines a party pool with a party composition to create more complex NPC parties.
|
||||
- Added basic chatter NPC Behaviour
|
||||
- Added `q.item.is_enchanted()`
|
||||
- Added `q.item.has_enchantment(minecraft:sharpness, 3)`
|
||||
- q.item.is_enchanted()
|
||||
- q.item.has_enchantment(minecraft:sharpness, 3)
|
||||
- Added `has_chosen_starter` & `get_starter_uuid` as available Molang functions
|
||||
- Added `marks`, `has_mark`, & `remove_marks` as available Molang functions for Pokémon
|
||||
- Added `marks`, `has_mark`, & `remove_marks` as available Molang functions for pokemon
|
||||
- Added Data Component support for species drops, eg `"components": {"minecraft:custom_model_data": 123}`
|
||||
- Added the new `sortOrder` field to mark entries, (defaults to 0 if not specified) which controls the order in which marks are rendered on the HUD, with higher numbers being rendered on top of lower numbers
|
||||
- Added optional `order` field to starter categories. It will allow explicitly sorting categories in the starter selection screen
|
||||
- SpeciesAdditions append vs override now matches wiki documentation
|
||||
- Added `weighted_choice` as a new feature type. It requires setting weights for each choice and allows developers to simplify the process of assigning random aspect choice based on marble chance
|
||||
- Added `q.world.spawn_loot_table_items(loot_table_id, x, y, z)` which spawns the items from the loot table at the position. (Use type: "minecraft:chest" for the loot table.)
|
||||
- Added `q.pokemon.entity` to access the entity of Pokémon.
|
||||
- Flamethrower and Seismic Toss had their action effect JSON cleaned up
|
||||
- Ride sounds can now be set as exclusive to passengers
|
||||
- Ride sounds no longer play when submerged unless specified with a new setting
|
||||
- NPC Trainers can now call a `command` animation when issuing a command in battle.
|
||||
- Added a q.failed function to move action effects.
|
||||
- Herd spawned Pokémon have their levels controlled differently. The `levelRange` property now acts as a clamp instead of a filter, with a new `herdLevelRange` property to do the filter behaviour.
|
||||
|
||||
### Particles
|
||||
- Added new sortOrder field to mark entries, (defaults to 0 if not specified) which controls the order in which marks are rendered on the HUD, with higher numbers being rendered on top of lower numbers
|
||||
- Added optional `order` field to starter categories. It will allow to explicitly sort categories in starter selection screen
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- Japanese
|
||||
- German
|
||||
- Ecuadorian Spanish
|
||||
- Simplified Chinese
|
||||
- Traditional Chinese
|
||||
- Korean
|
||||
@@ -1,9 +0,0 @@
|
||||
|
||||
- Nodemaker bug, it thinks jumps are possible from water up an entire block - they aint
|
||||
https://gyazo.com/759b8285e7c07046ff2e54adf0d7a7ac
|
||||
|
||||
- Why is magikarp trying to path through ice
|
||||
https://gyazo.com/ae230758c529f885eeb0dd91e60530d2
|
||||
|
||||
- We should use mixins to put the path node filtering from OmniPathNodeMaker in the base classes otherwise
|
||||
NPC wandering will be jank too.
|
||||
@@ -1,9 +0,0 @@
|
||||
- Some kind of particle effect for them? they're meant to have glowing eyes, so maybe some red particles on the eye locator
|
||||
--- global posers? stacked posers?
|
||||
--- red texture seems to be what some people wanted.
|
||||
|
||||
/- shoulder mounts part of it
|
||||
- omni boost
|
||||
- roar when player comes within reach, adjust levels
|
||||
|
||||
- Riding settings to control what the min scale is for a pokemon to be ridable.
|
||||
+23
-17
@@ -1,9 +1,9 @@
|
||||
|
||||
import utilities.isSnapshot
|
||||
import utilities.version
|
||||
import java.time.OffsetDateTime
|
||||
import java.time.ZoneOffset
|
||||
import java.time.format.DateTimeFormatter
|
||||
import utilities.isSnapshot
|
||||
import utilities.version
|
||||
|
||||
/*
|
||||
*
|
||||
@@ -18,15 +18,10 @@ import utilities.version
|
||||
plugins {
|
||||
id("cobblemon.base-conventions")
|
||||
id("cobblemon.publish-conventions")
|
||||
|
||||
id("net.kyori.blossom")
|
||||
id("org.jetbrains.gradle.plugin.idea-ext")
|
||||
}
|
||||
|
||||
architectury {
|
||||
common("neoforge", "fabric")
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven(url = "${rootProject.projectDir}/deps")
|
||||
maven(url = "https://api.modrinth.com/maven")
|
||||
@@ -35,33 +30,38 @@ repositories {
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
val mappingsAttribute = Attribute.of("net.minecraft.mappings", String::class.java)
|
||||
dependencies {
|
||||
implementation(libs.bundles.kotlin)
|
||||
modImplementation(libs.fabric.loader)
|
||||
modApi(libs.molang)
|
||||
compileOnly(libs.bundles.common.mixin.compileOnly)
|
||||
annotationProcessor(libs.mixinExtras.common)
|
||||
|
||||
api(libs.molang)
|
||||
|
||||
// Integrations
|
||||
compileOnlyApi(libs.jei.api)
|
||||
modCompileOnly(libs.bundles.common.integrations.compileOnly) {
|
||||
compileOnly(libs.bundles.common.integrations.compileOnly) {
|
||||
isTransitive = false
|
||||
}
|
||||
// LambDynamicLights is handled differently because we need the Mojang-mappings version of it.
|
||||
modCompileOnly(libs.lambDynamicLights) {
|
||||
capabilities {
|
||||
requireCapability("dev.lambdaurora.lambdynamiclights:api-mojmap")
|
||||
compileOnly(libs.lambDynamicLights) {
|
||||
attributes {
|
||||
attribute(mappingsAttribute, "mojmap")
|
||||
}
|
||||
}
|
||||
// Flywheel has no common dep so just pick one and don't use any platform specific code in common
|
||||
// modCompileOnly(libs.flywheelFabric)
|
||||
|
||||
// Showdown
|
||||
modCompileOnly(libs.graal.core)
|
||||
compileOnly(libs.graal.core)
|
||||
compileOnly(libs.graal.polyglot)
|
||||
|
||||
// Data Storage
|
||||
modCompileOnly(libs.bundles.mongo)
|
||||
compileOnly(libs.bundles.mongo)
|
||||
|
||||
// Unit Testing
|
||||
testImplementation(libs.bundles.unitTesting)
|
||||
testRuntimeOnly(libs.junit.platform)
|
||||
}
|
||||
|
||||
tasks.withType<Test> {
|
||||
@@ -72,8 +72,14 @@ tasks.withType<Test> {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.processResources {
|
||||
exclude("data/**/README.md")
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
|
||||
compilerOptions {
|
||||
freeCompilerArgs.addAll(
|
||||
"-Xno-param-assertions",
|
||||
"-Xno-call-assertions",
|
||||
"-Xno-receiver-assertions"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
maven.artifactId = mod
|
||||
maven.artifactId = mod
|
||||
fabric.loom.disableObfuscation=true
|
||||
+1
-1
@@ -36,7 +36,7 @@ public interface Bone {
|
||||
/**
|
||||
* Renders a particular bone in relation to a particular entity.
|
||||
*
|
||||
* @param context The render context this bone is being drawn for.
|
||||
* @param context The extractRenderState context this bone is being drawn for.
|
||||
* @param stack The current [MatrixStack] for the renderer
|
||||
* @param buffer The vertex consumer deployed by the renderer
|
||||
* @param packedLight The light level to be applied to the bone
|
||||
|
||||
+5
-7
@@ -9,20 +9,21 @@
|
||||
package com.cobblemon.mod.common.compat.lambdynamiclights;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.CobblemonEntities;
|
||||
import dev.lambdaurora.lambdynlights.api.DynamicLightsContext;
|
||||
import dev.lambdaurora.lambdynlights.api.DynamicLightsInitializer;
|
||||
import dev.lambdaurora.lambdynlights.api.entity.luminance.EntityLuminance;
|
||||
import dev.lambdaurora.lambdynlights.api.item.ItemLightSourceManager;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
|
||||
public class LambDynamicLightsInitializer implements DynamicLightsInitializer {
|
||||
public static final EntityLuminance.Type POKEMON_LUMINANCE = EntityLuminance.Type.registerSimple(
|
||||
ResourceLocation.fromNamespaceAndPath(Cobblemon.MODID, "pokemon"),
|
||||
Identifier.fromNamespaceAndPath(Cobblemon.MODID, "pokemon"),
|
||||
PokemonLuminance.INSTANCE
|
||||
);
|
||||
public static final EntityLuminance.Type PLAYER_LUMINANCE = EntityLuminance.Type.registerSimple(
|
||||
ResourceLocation.fromNamespaceAndPath(Cobblemon.MODID, "shoulder"),
|
||||
Identifier.fromNamespaceAndPath(Cobblemon.MODID, "shoulder"),
|
||||
PlayerLuminance.INSTANCE
|
||||
);
|
||||
|
||||
@@ -32,11 +33,8 @@ public class LambDynamicLightsInitializer implements DynamicLightsInitializer {
|
||||
|
||||
context.entityLightSourceManager().onRegisterEvent().register(ctx -> {
|
||||
ctx.register(EntityType.PLAYER, PlayerLuminance.INSTANCE);
|
||||
ctx.register(CobblemonEntities.POKEMON, PokemonLuminance.INSTANCE);
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings({"removal", "UnstableApiUsage"})
|
||||
@Override
|
||||
public void onInitializeDynamicLights(ItemLightSourceManager itemLightSourceManager) {}
|
||||
}
|
||||
|
||||
|
||||
+5
-4
@@ -10,10 +10,11 @@ package com.cobblemon.mod.common.compat.lambdynamiclights;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer;
|
||||
import com.cobblemon.mod.common.duck.PlayerDuck;
|
||||
import dev.lambdaurora.lambdynlights.api.entity.luminance.EntityLuminance;
|
||||
import dev.lambdaurora.lambdynlights.api.item.ItemLightSourceManager;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
@@ -25,7 +26,7 @@ import org.jetbrains.annotations.Range;
|
||||
|
||||
public final class PlayerLuminance extends CustomLuminance implements EntityLuminance {
|
||||
public static final PlayerLuminance INSTANCE = new PlayerLuminance();
|
||||
private static final TagKey<Item> POKEDEX = TagKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath(Cobblemon.MODID, "pokedex"));
|
||||
private static final TagKey<Item> POKEDEX = TagKey.create(Registries.ITEM, Identifier.fromNamespaceAndPath(Cobblemon.MODID, "pokedex"));
|
||||
|
||||
@Override
|
||||
public @NotNull Type type() {
|
||||
@@ -46,8 +47,8 @@ public final class PlayerLuminance extends CustomLuminance implements EntityLumi
|
||||
}
|
||||
|
||||
private @Range(from = 0L, to = 15L) static int shoulderLuminance(@NotNull ItemLightSourceManager itemLightSourceManager, @NotNull Player player) {
|
||||
final var leftShoulder = PokemonOnShoulderRenderer.shoulderDataFrom(player.getShoulderEntityLeft());
|
||||
final var rightShoulder = PokemonOnShoulderRenderer.shoulderDataFrom(player.getShoulderEntityRight());
|
||||
final var leftShoulder = PokemonOnShoulderRenderer.shoulderDataFrom(((PlayerDuck)player).getShoulderEntityLeft());
|
||||
final var rightShoulder = PokemonOnShoulderRenderer.shoulderDataFrom(((PlayerDuck)player).getShoulderEntityRight());
|
||||
|
||||
if (leftShoulder == null && rightShoulder == null) {
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface AvatarRenderStateDuck {
|
||||
@Nullable AbstractClientPlayer cobblemon$getMountedPlayer();
|
||||
void cobblemon$setMountedPlayer(@Nullable AbstractClientPlayer player);
|
||||
|
||||
@Nullable PokemonEntity cobblemon$getMountedPokemon();
|
||||
void cobblemon$setMountedPokemon(@Nullable PokemonEntity pokemonEntity);
|
||||
}
|
||||
@@ -30,4 +30,6 @@ public interface CameraDuck {
|
||||
|
||||
float cobblemon$getYRot();
|
||||
void cobblemon$setYRot(float yRot);
|
||||
|
||||
void cobblemon$markDirty();
|
||||
}
|
||||
|
||||
@@ -13,6 +13,5 @@ public interface ChannelDuck {
|
||||
void cobblemon$inverseAttenuation(float rolloffFactor);
|
||||
void cobblemon$clearFilters();
|
||||
|
||||
void cobblemon$applyReverb(float decayTime, float gain, float diffusion, float density);
|
||||
void cobblemon$clearReverb();
|
||||
// void cobblemon$exponentialAttenuation(float rolloff, float refDistance, float maxDistance);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
import com.cobblemon.mod.common.entity.PoseType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface LivingEntityRenderStateDuck {
|
||||
@Nullable LivingEntity cobblemon$getMountedEntity();
|
||||
void cobblemon$setMountedEntity(@Nullable LivingEntity entity);
|
||||
|
||||
float cobblemon$getMountedPartialTick();
|
||||
void cobblemon$setMountedPartialTick(float partialTick);
|
||||
|
||||
int cobblemon$getMountedSeatIndex();
|
||||
void cobblemon$setMountedSeatIndex(int seatIndex);
|
||||
|
||||
@Nullable String cobblemon$getMountedSeatLocator();
|
||||
void cobblemon$setMountedSeatLocator(@Nullable String seatLocator);
|
||||
|
||||
@Nullable PoseType cobblemon$getMountedPoseType();
|
||||
void cobblemon$setMountedPoseType(@Nullable PoseType poseType);
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
public interface PlayerDuck {
|
||||
@@ -15,4 +16,8 @@ public interface PlayerDuck {
|
||||
Vector3f getDriverInput();
|
||||
void setLastSentDriverInput(Vector3f driverInput);
|
||||
Vector3f getLastSentDriverInput();
|
||||
CompoundTag getShoulderEntityLeft();
|
||||
CompoundTag getShoulderEntityRight();
|
||||
void setShoulderEntityLeft(CompoundTag entityNbt);
|
||||
void setShoulderEntityRight(CompoundTag entityNbt);
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
import net.minecraft.world.item.crafting.RecipeManager;
|
||||
import net.minecraft.world.item.crafting.RecipeAccess;
|
||||
|
||||
public interface RecipeAwareSlot {
|
||||
void setRecipeManager(RecipeManager recipeManager);
|
||||
void setRecipeManager(RecipeAccess recipeManager);
|
||||
}
|
||||
|
||||
@@ -10,12 +10,12 @@ package com.cobblemon.mod.common.duck;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
|
||||
public interface SoundEngineDuck {
|
||||
|
||||
void pauseSounds(@Nullable ResourceLocation id, @Nullable SoundSource category);
|
||||
void pauseSounds(@Nullable Identifier id, @Nullable SoundSource category);
|
||||
|
||||
void resumeSounds(@Nullable ResourceLocation id, @Nullable SoundSource category);
|
||||
void resumeSounds(@Nullable Identifier id, @Nullable SoundSource category);
|
||||
}
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface SoundManagerDuck {
|
||||
|
||||
void pauseSounds(@Nullable ResourceLocation id, @Nullable SoundSource category);
|
||||
void pauseSounds(@Nullable Identifier id, @Nullable SoundSource category);
|
||||
|
||||
void resumeSounds(@Nullable ResourceLocation id, @Nullable SoundSource category);
|
||||
void resumeSounds(@Nullable Identifier id, @Nullable SoundSource category);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.projectile.AbstractArrow;
|
||||
import net.minecraft.world.entity.projectile.arrow.AbstractArrow;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -22,13 +22,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
|
||||
@Mixin(targets = "net.minecraft.world.entity.animal.Bee$BeeGrowCropGoal")
|
||||
@Mixin(targets = "net.minecraft.world.entity.animal.bee.Bee$BeeGrowCropGoal")
|
||||
public abstract class BeeEntityMixin {
|
||||
|
||||
@Unique
|
||||
private BlockState cobblemon$result = null;
|
||||
|
||||
@Inject(method = "tick()V", at = @At(
|
||||
@Inject(method = "tick", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/level/block/BonemealableBlock;performBonemeal(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/util/RandomSource;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;)V",
|
||||
shift = At.Shift.BY,
|
||||
|
||||
@@ -14,19 +14,26 @@ import com.cobblemon.mod.common.api.ai.config.task.PathToBeeHiveTaskConfig;
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.world.feature.SaccharineTreeFeature;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.util.ProblemReporter;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntitySpawnReason;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus;
|
||||
import net.minecraft.world.item.component.CustomData;
|
||||
import net.minecraft.world.item.component.TypedEntityData;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.BeehiveBlock;
|
||||
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
||||
import net.minecraft.world.level.storage.TagValueOutput;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.slf4j.Logger;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
@@ -38,25 +45,28 @@ import java.util.Objects;
|
||||
@Mixin(BeehiveBlockEntity.Occupant.class)
|
||||
public abstract class BeeOccupantMixin {
|
||||
|
||||
@Unique
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
@Inject(method = "createEntity", at = @At("RETURN"), cancellable = true)
|
||||
private void cobblemon$createEntity(Level level, BlockPos pos, CallbackInfoReturnable<Entity> cir) {
|
||||
// Needing to replicate all the post op stuff on the hive isn't great
|
||||
if (cir.getReturnValue() == null) {
|
||||
final BeehiveBlockEntity.Occupant occupant = (BeehiveBlockEntity.Occupant) (Object) this;
|
||||
CompoundTag compoundTag = occupant.entityData().copyTag();
|
||||
String id = compoundTag.getString("id");
|
||||
CompoundTag compoundTag = occupant.entityData().copyTagWithoutId();
|
||||
String id = compoundTag.getStringOr("id", "");
|
||||
Entity entity = null;
|
||||
if (id.equals(SaccharineTreeFeature.Companion.getPOKEMON_PLACEHOLD_ID())) {
|
||||
// Special case for Pokemon stuffed into a beenest upon world gen.
|
||||
// For technical reasons we cannot create them as full entities during world gen.
|
||||
// So we look for this special id tag and complete the entity when it attempts to exit a hive.
|
||||
if (compoundTag.contains("pokemonProperties")) {
|
||||
String properties = compoundTag.getString("pokemonProperties");
|
||||
String properties = compoundTag.getString("pokemonProperties").get();
|
||||
PokemonProperties pokemon = PokemonProperties.Companion.parse(properties);
|
||||
entity = pokemon.createEntity(level);
|
||||
}
|
||||
} else {
|
||||
entity = EntityType.loadEntityRecursive(compoundTag, level, (entityx) -> entityx);
|
||||
entity = EntityType.loadEntityRecursive(compoundTag, level, EntitySpawnReason.LOAD, (entityx) -> entityx);
|
||||
}
|
||||
|
||||
if (entity instanceof PokemonEntity pokemonEntity) {
|
||||
@@ -76,11 +86,11 @@ public abstract class BeeOccupantMixin {
|
||||
// Block has likely been destroyed
|
||||
var center = pos.getCenter();
|
||||
newPos = new Vec3(
|
||||
center.x + level.random.nextFloat() * 0.6 - 0.3,
|
||||
center.y + level.random.nextFloat() * 0.6 - 0.3,
|
||||
center.z + level.random.nextFloat() * 0.6 - 0.3
|
||||
center.x + level.getRandom().nextFloat() * 0.6 - 0.3,
|
||||
center.y + level.getRandom().nextFloat() * 0.6 - 0.3,
|
||||
center.z + level.getRandom().nextFloat() * 0.6 - 0.3
|
||||
);
|
||||
newYaw = level.random.nextFloat() * 360F;
|
||||
newYaw = level.getRandom().nextFloat() * 360F;
|
||||
if (brain.checkMemory(CobblemonMemories.HIVE_LOCATION, MemoryStatus.REGISTERED)) {
|
||||
brain.eraseMemory(CobblemonMemories.HIVE_LOCATION);
|
||||
}
|
||||
@@ -100,7 +110,7 @@ public abstract class BeeOccupantMixin {
|
||||
if (state.is(BlockTags.BEEHIVES, (blockStateBase) -> blockStateBase.hasProperty(BeehiveBlock.HONEY_LEVEL))) {
|
||||
int i = state.getValue(BeehiveBlock.HONEY_LEVEL);
|
||||
if (i < 5) {
|
||||
int j = level.random.nextInt(100) == 0 ? 2 : 1;
|
||||
int j = level.getRandom().nextInt(100) == 0 ? 2 : 1;
|
||||
if (i + j > 5) {
|
||||
--j;
|
||||
}
|
||||
@@ -117,16 +127,19 @@ public abstract class BeeOccupantMixin {
|
||||
@Inject(method = "of", at = @At("HEAD"), cancellable = true)
|
||||
private static void cobblemon$of(Entity entity, CallbackInfoReturnable<BeehiveBlockEntity.Occupant> cir) {
|
||||
if (entity instanceof PokemonEntity pokemonEntity) {
|
||||
List<String> IGNORED_BEE_TAGS = Arrays.asList("Air", "ArmorDropChances", "ArmorItems", "CanPickUpLoot", "DeathTime", "FallDistance", "FallFlying", "Fire", "HandDropChances", "HandItems", "HurtByTimestamp", "HurtTime", "LeftHanded", "Motion", "NoGravity", "OnGround", "PortalCooldown", "Pos", "Rotation", "Passengers", "leash", "UUID");
|
||||
CompoundTag compoundTag = new CompoundTag();
|
||||
entity.save(compoundTag);
|
||||
Objects.requireNonNull(compoundTag);
|
||||
IGNORED_BEE_TAGS.forEach(compoundTag::remove);
|
||||
boolean hasNectar = pokemonEntity.getBrain().checkMemory(CobblemonMemories.HAS_NECTAR, MemoryStatus.REGISTERED)
|
||||
&& pokemonEntity.getBrain().getMemory(CobblemonMemories.HAS_NECTAR).orElse(false);
|
||||
cir.setReturnValue(new BeehiveBlockEntity.Occupant(CustomData.of(compoundTag), 0, hasNectar ? 2400 : 600));
|
||||
cir.cancel();
|
||||
try (ProblemReporter.ScopedCollector reporter = new ProblemReporter.ScopedCollector(pokemonEntity.problemPath(), LOGGER)) {
|
||||
List<String> IGNORED_BEE_TAGS = BeehiveBlockEntity.IGNORED_BEE_TAGS;
|
||||
TagValueOutput output = TagValueOutput.createWithContext(reporter, pokemonEntity.registryAccess());
|
||||
pokemonEntity.save(output);
|
||||
Objects.requireNonNull(output);
|
||||
IGNORED_BEE_TAGS.forEach(output::discard);
|
||||
CompoundTag entityTag = output.buildResult();
|
||||
boolean hasNectar = pokemonEntity.getBrain().checkMemory(CobblemonMemories.HAS_NECTAR, MemoryStatus.REGISTERED)
|
||||
&& pokemonEntity.getBrain().getMemory(CobblemonMemories.HAS_NECTAR).orElse(false);
|
||||
cir.setReturnValue(new BeehiveBlockEntity.Occupant(TypedEntityData.of(pokemonEntity.getType(), entityTag), 0, hasNectar ? 2400 : 600));
|
||||
cir.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ package com.cobblemon.mod.common.mixin;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.mixin.accessor.BeeDataAccessor;
|
||||
import com.cobblemon.mod.common.mixin.accessor.BeehiveBlockEntityAccessor;
|
||||
import com.cobblemon.mod.common.mixin.accessor.BlockEntityAccessor;
|
||||
import com.google.common.collect.Lists;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
@@ -59,8 +58,8 @@ public abstract class BeehiveBlockEntityMixin {
|
||||
}
|
||||
if (isPokemon) {
|
||||
return BeehiveBlockEntityAccessor.releaseOccupant(
|
||||
((BlockEntityAccessor) blockEntityAccessor).getLevel(),
|
||||
((BlockEntityAccessor) blockEntityAccessor).getWorldPosition(),
|
||||
blockEntity.getLevel(),
|
||||
blockEntity.getBlockPos(),
|
||||
state,
|
||||
occupant,
|
||||
list,
|
||||
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRenderer;
|
||||
import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRendererRegistry;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(BlockEntityWithoutLevelRenderer.class)
|
||||
public class BuiltinModelItemRendererMixin {
|
||||
|
||||
@Inject(method = "renderByItem", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$useDynamicItemRenderer(ItemStack stack, ItemDisplayContext mode, PoseStack matrices, MultiBufferSource vertexConsumers, int light, int overlay, CallbackInfo ci) {
|
||||
CobblemonBuiltinItemRenderer renderer = CobblemonBuiltinItemRendererRegistry.INSTANCE.rendererOf(stack.getItem());
|
||||
if (renderer != null) {
|
||||
renderer.render(stack, mode, matrices, vertexConsumers, light, overlay);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.duck.ChannelDuck;
|
||||
import com.mojang.blaze3d.audio.Channel;
|
||||
import org.lwjgl.openal.AL10;
|
||||
import org.lwjgl.openal.EXTEfx;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
@Mixin(Channel.class)
|
||||
public abstract class ChannelMixin implements ChannelDuck {
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private int source;
|
||||
|
||||
// Id of filter applied when sound is obstructed
|
||||
private int cobblemon$lowPassFilterId = 0;
|
||||
|
||||
@Override
|
||||
public void cobblemon$applyLowPassFilter(float gain, float hfGain) {
|
||||
// Delete old filter if it exists
|
||||
if (cobblemon$lowPassFilterId != 0) {
|
||||
AL10.alSourcei(source, EXTEfx.AL_DIRECT_FILTER, 0); // Detach filter from source
|
||||
EXTEfx.alDeleteFilters(cobblemon$lowPassFilterId); // Delete old filter
|
||||
cobblemon$lowPassFilterId = 0;
|
||||
}
|
||||
|
||||
// Generate a fresh filter
|
||||
int filterId = EXTEfx.alGenFilters();
|
||||
if (!EXTEfx.alIsFilter(filterId)) {
|
||||
System.err.println("Failed to create OpenAL low-pass filter");
|
||||
return;
|
||||
}
|
||||
|
||||
EXTEfx.alFilteri(filterId, EXTEfx.AL_FILTER_TYPE, EXTEfx.AL_FILTER_LOWPASS);
|
||||
EXTEfx.alFilterf(filterId, EXTEfx.AL_LOWPASS_GAIN, gain);
|
||||
EXTEfx.alFilterf(filterId, EXTEfx.AL_LOWPASS_GAINHF, hfGain);
|
||||
|
||||
AL10.alSourcei(source, EXTEfx.AL_DIRECT_FILTER, filterId);
|
||||
|
||||
// Save the new filter ID
|
||||
cobblemon$lowPassFilterId = filterId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$inverseAttenuation(float rolloffFactor) {
|
||||
AL10.alSourcei(source, AL10.AL_DISTANCE_MODEL, AL10.AL_INVERSE_DISTANCE);
|
||||
AL10.alSourcef(source, AL10.AL_ROLLOFF_FACTOR, rolloffFactor);
|
||||
AL10.alSourcef(source, AL10.AL_REFERENCE_DISTANCE, 1.0f);
|
||||
AL10.alSourcef(source, AL10.AL_MAX_DISTANCE, 0.0f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$clearFilters() {
|
||||
AL10.alSourcei(source, EXTEfx.AL_DIRECT_FILTER, 0);
|
||||
|
||||
if (EXTEfx.alIsFilter(cobblemon$lowPassFilterId)) {
|
||||
EXTEfx.alDeleteFilters(cobblemon$lowPassFilterId);
|
||||
cobblemon$lowPassFilterId = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import static com.cobblemon.mod.common.datafixer.CobblemonSchemas.VERSION_KEY;
|
||||
|
||||
import com.cobblemon.mod.common.datafixer.CobblemonSchemas;
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.IntTag;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.util.datafix.DataFixTypes;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.level.chunk.storage.ChunkStorage;
|
||||
import net.minecraft.world.level.storage.DimensionDataStorage;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(ChunkStorage.class)
|
||||
public class ChunkStorageMixin {
|
||||
//Modifies the NBT returned by the vanilla upgradeChunkTag to also incorporate cobblemon fixup stuff
|
||||
@ModifyExpressionValue(
|
||||
method = "upgradeChunkTag(Lnet/minecraft/resources/ResourceKey;Ljava/util/function/Supplier;Lnet/minecraft/nbt/CompoundTag;Ljava/util/Optional;)Lnet/minecraft/nbt/CompoundTag;",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/util/datafix/DataFixTypes;updateToCurrentVersion(Lcom/mojang/datafixers/DataFixer;Lnet/minecraft/nbt/CompoundTag;I)Lnet/minecraft/nbt/CompoundTag;"
|
||||
)
|
||||
)
|
||||
public CompoundTag cobblemon$doChunkFix(
|
||||
CompoundTag vanillaFixed
|
||||
) {
|
||||
int curVersion = vanillaFixed.contains(VERSION_KEY) ? vanillaFixed.getInt(VERSION_KEY) : 0;
|
||||
return DataFixTypes.CHUNK.update(CobblemonSchemas.getDATA_FIXER(), vanillaFixed, curVersion, CobblemonSchemas.DATA_VERSION);
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
@Mixin(ClientPacketListener.class)
|
||||
@@ -35,17 +36,17 @@ public class ClientPacketListenerMixin {
|
||||
for (int passenger : packet.getPassengers()) {
|
||||
passengers.add(this.level.getEntity(passenger));
|
||||
}
|
||||
pokemon.getOccupiedSeats().values().stream()
|
||||
Arrays
|
||||
.stream(pokemon.getOccupiedSeats())
|
||||
.filter(x -> !passengers.contains(x))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(Entity::stopRiding);
|
||||
|
||||
// Mount passengers not yet in the map
|
||||
var currentPassengers = new ArrayList<>(pokemon.getOccupiedSeats().values());
|
||||
var occupiedSeats = Arrays.asList(pokemon.getOccupiedSeats());
|
||||
passengers.stream()
|
||||
.filter(x -> !currentPassengers.contains(x))
|
||||
.filter(x -> !occupiedSeats.contains(x))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(x -> x.startRiding(pokemon, true));
|
||||
.forEach(x -> x.startRiding(pokemon, true, true));
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.block.dispenser.DispenserBehaviorRegistry;
|
||||
import net.minecraft.core.dispenser.DispenseItemBehavior;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(DispenseItemBehavior.class)
|
||||
public interface DispenseItemBehaviourMixin {
|
||||
@Inject(method = "bootStrap", at = @At("TAIL"))
|
||||
private static void addCobblemonDispenserBehaviors(CallbackInfo ci) {
|
||||
DispenserBehaviorRegistry.INSTANCE.registerDispenserBehaviors();
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResultHolder;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.EnderpearlItem;
|
||||
@@ -28,7 +28,7 @@ import java.util.Comparator;
|
||||
@Mixin(EnderpearlItem.class)
|
||||
public abstract class EnderPearlItemMixin {
|
||||
@Inject(method = "use", at = @At(value = "HEAD"), cancellable = true)
|
||||
private void cobblemon$use(Level level, Player player, InteractionHand usedHand, CallbackInfoReturnable<InteractionResultHolder<ItemStack>> cir) {
|
||||
private void cobblemon$use(Level level, Player player, InteractionHand usedHand, CallbackInfoReturnable<InteractionResult> cir) {
|
||||
double range = player.entityInteractionRange();
|
||||
Entity closestEntity = level.getEntities(player, AABB.ofSize(player.position(), range, range, range)).stream()
|
||||
.filter(entity -> isLookingAt(player, entity))
|
||||
@@ -36,7 +36,7 @@ public abstract class EnderPearlItemMixin {
|
||||
.orElse(null);
|
||||
|
||||
if (closestEntity instanceof PokemonEntity pokemonEntity) {
|
||||
if (player.isCrouching() && pokemonEntity.getOwnerUUID() == player.getUUID()) {
|
||||
if (player.isCrouching() && pokemonEntity.isOwnedBy(player)) {
|
||||
cir.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import com.cobblemon.mod.common.pokemon.ai.EntityBehaviour;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.ai.goal.AvoidEntityGoal;
|
||||
import net.minecraft.world.entity.animal.Fox;
|
||||
import net.minecraft.world.entity.animal.fox.Fox;
|
||||
import net.minecraft.world.entity.monster.Creeper;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
+5
-64
@@ -9,19 +9,11 @@
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.client.CobblemonClient;
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState;
|
||||
import com.cobblemon.mod.common.entity.PosableEntity;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import net.minecraft.client.renderer.LevelRenderer;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
|
||||
import net.minecraft.client.renderer.entity.EntityRenderer;
|
||||
import net.minecraft.client.resources.PlayerSkin;
|
||||
import net.minecraft.client.renderer.entity.player.AvatarRenderer;
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.entity.player.PlayerModelType;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
@@ -33,7 +25,7 @@ import java.util.Map;
|
||||
@Mixin(EntityRenderDispatcher.class)
|
||||
public class EntityRenderDispatcherMixin {
|
||||
|
||||
@Shadow private Map<PlayerSkin.Model, EntityRenderer<? extends Player>> playerRenderers;
|
||||
@Shadow private Map<PlayerModelType, AvatarRenderer<AbstractClientPlayer>> playerRenderers;
|
||||
|
||||
@Inject(
|
||||
method = "onResourceManagerReload",
|
||||
@@ -43,55 +35,4 @@ public class EntityRenderDispatcherMixin {
|
||||
CobblemonClient.INSTANCE.onAddLayer(this.playerRenderers);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "renderHitbox(Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;Lnet/minecraft/world/entity/Entity;FFFF)V",
|
||||
at = @At(value = "TAIL")
|
||||
)
|
||||
private static void renderLocators(
|
||||
PoseStack poseStack,
|
||||
VertexConsumer buffer,
|
||||
Entity entity,
|
||||
float red,
|
||||
float green,
|
||||
float blue,
|
||||
float alpha,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
if (entity instanceof PosableEntity posableEntity) {
|
||||
if (posableEntity.getDelegate() instanceof PosableState state) {
|
||||
state.getLocatorStates().forEach((locator, matrix) -> {
|
||||
poseStack.pushPose();
|
||||
Vec3 pos = matrix.getOrigin().subtract(entity.position());
|
||||
LevelRenderer.renderLineBox(
|
||||
poseStack,
|
||||
buffer,
|
||||
AABB.ofSize(pos, 0.25, 0.25, 0.25),
|
||||
0F,
|
||||
1F,
|
||||
0F,
|
||||
1F
|
||||
);
|
||||
|
||||
/*if (locator.contains("middle")){
|
||||
PoseStack.Pose pose = poseStack.last();
|
||||
Vector3f vec = matrix.getMatrix().getRotation(new AxisAngle4f()).transform(new Vector3f(0, 0, -1));
|
||||
buffer.addVertex(pose, pos.toVector3f()).setColor(0xffff00ff).setNormal(pose, vec.x, vec.y, vec.z); //Forward, pink
|
||||
buffer.addVertex(pose, (float)(pos.x() + vec.x), (float)(pos.y() + vec.y), (float)(pos.z() + vec.z)).setColor(0xffff00ff).setNormal(pose, vec.x, vec.y, vec.z);
|
||||
|
||||
vec = matrix.getMatrix().getRotation(new AxisAngle4f()).transform(new Vector3f(0, 1, 0));
|
||||
buffer.addVertex(pose, pos.toVector3f()).setColor(0xffffff00).setNormal(pose, vec.x, vec.y, vec.z); //Up, yellow
|
||||
buffer.addVertex(pose, (float)(pos.x() + vec.x), (float)(pos.y() + vec.y), (float)(pos.z() + vec.z)).setColor(0xffffff00).setNormal(pose, vec.x, vec.y, vec.z);
|
||||
|
||||
vec = matrix.getMatrix().getRotation(new AxisAngle4f()).transform(new Vector3f(-1, 0, 0));
|
||||
buffer.addVertex(pose, pos.toVector3f()).setColor(0xff00ffff).setNormal(pose, vec.x, vec.y, vec.z); //Left, cyan
|
||||
buffer.addVertex(pose, (float)(pos.x() + vec.x), (float)(pos.y() + vec.y), (float)(pos.z() + vec.z)).setColor(0xff00ffff).setNormal(pose, vec.x, vec.y, vec.z);
|
||||
}*/
|
||||
|
||||
|
||||
poseStack.popPose();
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.ai.goal.AvoidEntityGoal;
|
||||
import net.minecraft.world.entity.monster.AbstractSkeleton;
|
||||
import net.minecraft.world.entity.monster.skeleton.AbstractSkeleton;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
public class EntityStorageMixin {
|
||||
//Modifies the NBT returned by the vanilla upgradeChunkTag to also incorporate cobblemon fixup stuff
|
||||
@ModifyExpressionValue(
|
||||
method = "method_31731(Lnet/minecraft/world/level/ChunkPos;Ljava/util/Optional;)Lnet/minecraft/world/level/entity/ChunkEntities;",
|
||||
method = "lambda$loadEntities$0",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/level/chunk/storage/SimpleRegionStorage;upgradeChunkTag(Lnet/minecraft/nbt/CompoundTag;I)Lnet/minecraft/nbt/CompoundTag;"
|
||||
@@ -32,7 +32,7 @@ public class EntityStorageMixin {
|
||||
public CompoundTag cobblemon$doEntityFix(
|
||||
CompoundTag vanillaFixed
|
||||
) {
|
||||
int curVersion = vanillaFixed.contains(VERSION_KEY) ? vanillaFixed.getInt(VERSION_KEY) : 0;
|
||||
int curVersion = vanillaFixed.getIntOr(VERSION_KEY, 0);
|
||||
CompoundTag newTag = DataFixTypes.ENTITY_CHUNK.update(CobblemonSchemas.getDATA_FIXER(), vanillaFixed, curVersion, CobblemonSchemas.DATA_VERSION);
|
||||
newTag.put(VERSION_KEY, IntTag.valueOf(CobblemonSchemas.DATA_VERSION));
|
||||
return newTag;
|
||||
|
||||
@@ -15,17 +15,18 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import com.cobblemon.mod.common.villager.VillagerGatherableItems;
|
||||
|
||||
import java.util.Objects;
|
||||
import net.minecraft.world.entity.npc.Villager;
|
||||
import net.minecraft.world.entity.npc.VillagerProfession;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.npc.villager.Villager;
|
||||
import net.minecraft.world.entity.npc.villager.VillagerProfession;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
@Mixin(Villager.class)
|
||||
public abstract class EntityVillagerMixin {
|
||||
|
||||
@Inject(method = "wantsToPickUp", at = @At(value = "RETURN"), cancellable = true)
|
||||
private void cobblemon$canGather(ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
|
||||
private void cobblemon$canGather(ServerLevel serverLevel, ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
|
||||
final Villager villager = (Villager) (Object) this;
|
||||
if (ci.getReturnValue() == false && Objects.equals(villager.getVillagerData().getProfession(), VillagerProfession.FARMER) && villager.getInventory().canAddItem(stack)) {
|
||||
if (!ci.getReturnValue() && Objects.equals(villager.getVillagerData().profession().value(), VillagerProfession.FARMER) && villager.getInventory().canAddItem(stack)) {
|
||||
if(VillagerGatherableItems.INSTANCE.getVillagerGatherableItems().contains(stack.getItem()))
|
||||
ci.setReturnValue(true);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.CobblemonItems;
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents;
|
||||
import com.cobblemon.mod.common.api.events.item.LeftoversCreatedEvent;
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
|
||||
import kotlin.Unit;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.food.FoodProperties;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.component.Consumable;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(FoodProperties.class)
|
||||
public class FoodPropertiesMixin {
|
||||
@Inject(method = "onConsume", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/food/FoodData;eat(Lnet/minecraft/world/food/FoodProperties;)V"))
|
||||
public void dropLeftOvers(Level level, LivingEntity user, ItemStack stack, Consumable consumable, CallbackInfo ci) {
|
||||
if (!level.isClientSide()) {
|
||||
if (stack.is(CobblemonItemTags.LEAVES_LEFTOVERS) && level.getRandom().nextDouble() < Cobblemon.config.getAppleLeftoversChance()) {
|
||||
ItemStack leftovers = new ItemStack(CobblemonItems.LEFTOVERS);
|
||||
CobblemonEvents.LEFTOVERS_CREATED.postThen(
|
||||
new LeftoversCreatedEvent(user, leftovers),
|
||||
_ -> Unit.INSTANCE,
|
||||
leftoversCreatedEvent -> {
|
||||
user.handleExtraItemsCreatedOnUse(leftoversCreatedEvent.getLeftovers());
|
||||
return Unit.INSTANCE;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.item.ItemProperties;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(ItemProperties.class)
|
||||
public class ItemPropertiesMixin {
|
||||
|
||||
// Mixins into the fishing rod's register() lambda expression
|
||||
// Without this, the fishing rod item model appears cast when using a PokeRod in the other hand
|
||||
@Inject(method = "method_27883", at = @At(value = "RETURN", ordinal = 1), cancellable = true)
|
||||
private static void cobblemon$preventRodMixup(ItemStack itemStack, ClientLevel clientLevel, LivingEntity livingEntity, int i, CallbackInfoReturnable<Float> cir) {
|
||||
if (!(livingEntity instanceof Player) || ((Player) livingEntity).fishing instanceof PokeRodFishingBobberEntity) {
|
||||
cir.setReturnValue(0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.ItemInteractionResult;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
@@ -35,8 +35,8 @@ import static net.minecraft.world.level.block.LecternBlock.HAS_BOOK;
|
||||
@Mixin(LecternBlock.class)
|
||||
public abstract class LecternBlockMixin {
|
||||
@Inject(method = "useItemOn", at = @At(value = "HEAD"), cancellable = true)
|
||||
private void cobblemon$useItemOn(ItemStack itemStack, BlockState blockState, Level world, BlockPos blockPos, Player player, InteractionHand interactionHand, BlockHitResult blockHitResult, CallbackInfoReturnable<ItemInteractionResult> cir) {
|
||||
if (!world.isClientSide && itemStack.getItem() instanceof PokedexItem) {
|
||||
private void cobblemon$useItemOn(ItemStack itemStack, BlockState blockState, Level world, BlockPos blockPos, Player player, InteractionHand interactionHand, BlockHitResult blockHitResult, CallbackInfoReturnable<InteractionResult> cir) {
|
||||
if (!world.isClientSide() && itemStack.getItem() instanceof PokedexItem) {
|
||||
BlockEntity blockEntity = world.getBlockEntity(blockPos);
|
||||
if (!blockState.getValue(HAS_BOOK)
|
||||
&& blockEntity instanceof net.minecraft.world.level.block.entity.LecternBlockEntity
|
||||
@@ -53,9 +53,9 @@ public abstract class LecternBlockMixin {
|
||||
if (lecternEntity instanceof LecternBlockEntity) {
|
||||
((LecternBlockEntity) lecternEntity).setItemStack((pokedexItemStack));
|
||||
world.playSound(null, blockPos, CobblemonSounds.POKEDEX_CLOSE, SoundSource.BLOCKS, 0.5F, 1.25F);
|
||||
cir.setReturnValue(ItemInteractionResult.SUCCESS);
|
||||
cir.setReturnValue(InteractionResult.SUCCESS);
|
||||
} else {
|
||||
cir.setReturnValue(itemStack.isEmpty() && interactionHand == InteractionHand.MAIN_HAND ? ItemInteractionResult.SKIP_DEFAULT_BLOCK_INTERACTION : ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION);
|
||||
cir.setReturnValue(itemStack.isEmpty() && interactionHand == InteractionHand.MAIN_HAND ? InteractionResult.PASS : InteractionResult.TRY_WITH_EMPTY_HAND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import java.util.List;
|
||||
@Mixin(LightningBolt.class)
|
||||
public abstract class LightningBoltMixin {
|
||||
|
||||
@Inject(method = "spawnFire", at = @At(value = "Head"), cancellable = true)
|
||||
@Inject(method = "spawnFire", at = @At(value = "HEAD"), cancellable = true)
|
||||
private void cobblemon$spawnFire(int extraIgnitions, CallbackInfo ci) {
|
||||
// This prevents fire from spawning around Pokemon who otherwise should be immune to lightning and effectively absorb the hit
|
||||
final LightningBolt lightningBolt = (LightningBolt) (Object) this;
|
||||
@@ -41,4 +41,4 @@ public abstract class LightningBoltMixin {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,18 +15,23 @@ import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffectRegistry;
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle;
|
||||
import com.cobblemon.mod.common.api.riding.Seat;
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.SubmarineBehaviour;
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate;
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.ClipContext;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
@@ -55,8 +60,8 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
|
||||
return cobblemon$orientationController;
|
||||
}
|
||||
|
||||
@Inject(method = "onEffectRemoved", at = @At(value = "TAIL"))
|
||||
private void cobblemon$onEffectRemoved(MobEffectInstance effect, CallbackInfo ci) {
|
||||
@Inject(method = "removeEffect", at = @At(value = "TAIL"))
|
||||
private void cobblemon$onEffectRemoved(Holder<MobEffect> effect, CallbackInfoReturnable<Boolean> cir) {
|
||||
final LivingEntity entity = (LivingEntity) (Object) this;
|
||||
if (entity instanceof ServerPlayer) {
|
||||
ShoulderEffectRegistry.INSTANCE.onEffectEnd((ServerPlayer) entity);
|
||||
@@ -76,27 +81,40 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
|
||||
Entity vehicle = this.getVehicle();
|
||||
if (vehicle instanceof PokemonEntity pokemonEntity && pokemonEntity.getDelegate() instanceof PokemonClientDelegate delegate) {
|
||||
int seatIndex = pokemonEntity.getPassengers().indexOf(this);
|
||||
Seat seat = pokemonEntity.getSeats().get(seatIndex);
|
||||
MatrixWrapper locator = delegate.getLocatorStates().get(seat.getLocator());
|
||||
if (seatIndex >= 0 && seatIndex < pokemonEntity.getSeats().size()) {
|
||||
Seat seat = pokemonEntity.getSeats().get(seatIndex);
|
||||
MatrixWrapper locator = delegate.getLocatorStates().get(seat.getLocator());
|
||||
if (locator != null) {
|
||||
Vec3 locatorOffset = new Vec3(locator.getMatrix().getTranslation(new Vector3f()));
|
||||
Vec3 eyePosition = cobblemon$getEyePosition(partialTicks, pokemonEntity, locatorOffset);
|
||||
return cobblemon$pickFromEyePosition(hitDistance, partialTicks, hitFluids, eyePosition);
|
||||
}
|
||||
}
|
||||
|
||||
Vec3 locatorOffset = new Vec3(locator.getMatrix().getTranslation(new Vector3f()));
|
||||
|
||||
Vec3 eyePosition = cobblemon$getEyePosition(partialTicks, pokemonEntity, locatorOffset);
|
||||
|
||||
Vec3 viewVector = this.getViewVector(partialTicks);
|
||||
Vec3 viewDistanceVector = eyePosition.add(viewVector.x * hitDistance, viewVector.y * hitDistance, viewVector.z * hitDistance);
|
||||
|
||||
return this.level()
|
||||
.clip(
|
||||
new ClipContext(
|
||||
eyePosition, viewDistanceVector, ClipContext.Block.OUTLINE, hitFluids ? net.minecraft.world.level.ClipContext.Fluid.ANY : net.minecraft.world.level.ClipContext.Fluid.NONE, this
|
||||
)
|
||||
);
|
||||
if ((Object) this instanceof RidePassenger ridePassenger) {
|
||||
Vec3 rideEyePosition = ridePassenger.cobblemon$getRideEyePos();
|
||||
if (!rideEyePosition.equals(Vec3.ZERO)) {
|
||||
return cobblemon$pickFromEyePosition(hitDistance, partialTicks, hitFluids, rideEyePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.pick(hitDistance, partialTicks, hitFluids);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private @NotNull HitResult cobblemon$pickFromEyePosition(double hitDistance, float partialTicks, boolean hitFluids, Vec3 eyePosition) {
|
||||
Vec3 viewVector = this.getViewVector(partialTicks);
|
||||
Vec3 viewDistanceVector = eyePosition.add(viewVector.x * hitDistance, viewVector.y * hitDistance, viewVector.z * hitDistance);
|
||||
|
||||
return this.level()
|
||||
.clip(
|
||||
new ClipContext(
|
||||
eyePosition, viewDistanceVector, ClipContext.Block.OUTLINE, hitFluids ? net.minecraft.world.level.ClipContext.Fluid.ANY : net.minecraft.world.level.ClipContext.Fluid.NONE, this
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private Vec3 cobblemon$getEyePosition(float partialTicks, PokemonEntity pokemonEntity, Vec3 locatorOffset) {
|
||||
OrientationController controller = this.getOrientationController();
|
||||
@@ -118,20 +136,6 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
|
||||
this.cobblemon$orientationController.tick();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void absMoveTo(double x, double y, double z, float yaw, float pitch) {
|
||||
if (cobblemon$orientationController.getActive()) {
|
||||
this.absMoveTo(x, y, z);
|
||||
this.setYRot(yaw % 360.0f);
|
||||
this.setXRot(pitch % 360.0f);
|
||||
this.yRotO = this.getYRot();
|
||||
this.xRotO = this.getXRot();
|
||||
} else {
|
||||
this.absMoveTo(x, y, z);
|
||||
this.absRotateTo(yaw, pitch);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "decreaseAirSupply", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$conditionalWaterBreathing(
|
||||
int currentAir,
|
||||
@@ -159,4 +163,10 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "stopRiding", at = @At("HEAD"))
|
||||
public void cobblemon$resetOrientationOnDismount(CallbackInfo ci) {
|
||||
LivingEntity player = (LivingEntity)(Object)this;
|
||||
if (!(player.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
|
||||
controllableVehicle.getOrientationController().setActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.server.ServerInterface;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(ServerLevel.class)
|
||||
public abstract class MinecraftDedicatedServerMixin implements ServerInterface {
|
||||
|
||||
@Inject(method = "shouldDiscardEntity", at = @At(value = "HEAD"), cancellable = true)
|
||||
public void cobblemon$allowPokemonSpawns(Entity entity, CallbackInfoReturnable<Boolean> callback) {
|
||||
if (entity instanceof PokemonEntity) {
|
||||
callback.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.block.entity.DiscShelfBlockEntity;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.NoteBlock;
|
||||
import net.minecraft.world.level.block.state.properties.NoteBlockInstrument;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(NoteBlock.class)
|
||||
public abstract class NoteBlockMixin {
|
||||
@Inject(method = "triggerEvent", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$triggerTMShelfSequencer(BlockState state, Level level, BlockPos pos, int type, int data, CallbackInfoReturnable<Boolean> cir) {
|
||||
final BlockPos shelfPos = pos.below();
|
||||
final BlockEntity blockEntity = level.getBlockEntity(shelfPos);
|
||||
if (!(blockEntity instanceof DiscShelfBlockEntity discShelfBlockEntity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!level.isClientSide) {
|
||||
final BlockPos instrumentPos = shelfPos.below();
|
||||
final SoundEvent soundEvent;
|
||||
if (level.getBlockState(instrumentPos).isAir()) {
|
||||
soundEvent = SoundEvents.NOTE_BLOCK_BIT.value();
|
||||
} else {
|
||||
final NoteBlockInstrument instrument = level.getBlockState(instrumentPos).instrument();
|
||||
final Holder<SoundEvent> holder = instrument.getSoundEvent();
|
||||
soundEvent = holder.value();
|
||||
}
|
||||
discShelfBlockEntity.onNoteBlockPulse(level, pos, soundEvent);
|
||||
}
|
||||
|
||||
// Suppress vanilla note-block playback while it is on top of a TM Shelf.
|
||||
cir.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,8 @@
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.api.snowstorm.ParticleMaterials;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.cobblemon.mod.common.client.particle.SnowstormParticleGroup;
|
||||
import java.util.ArrayList;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
@@ -17,8 +18,10 @@ import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.List;
|
||||
import net.minecraft.client.particle.ParticleGroup;
|
||||
import net.minecraft.client.particle.ParticleEngine;
|
||||
import net.minecraft.client.particle.ParticleRenderType;
|
||||
|
||||
@@ -31,7 +34,21 @@ final class ParticleManagerMixin {
|
||||
|
||||
@Inject(at = @At("RETURN"), method = "<clinit>")
|
||||
private static void lodestone$addTypes(CallbackInfo ci) {
|
||||
RENDER_ORDER = ImmutableList.<ParticleRenderType>builder().addAll(RENDER_ORDER)
|
||||
.add(ParticleMaterials.INSTANCE.getADD(), ParticleMaterials.INSTANCE.getALPHA(), ParticleMaterials.INSTANCE.getBLEND(), ParticleMaterials.INSTANCE.getOPAQUE()).build();
|
||||
ArrayList<ParticleRenderType> types = new ArrayList<>(RENDER_ORDER);
|
||||
types.add(ParticleMaterials.INSTANCE.getADD());
|
||||
types.add(ParticleMaterials.INSTANCE.getALPHA());
|
||||
types.add(ParticleMaterials.INSTANCE.getBLEND());
|
||||
types.add(ParticleMaterials.INSTANCE.getOPAQUE());
|
||||
RENDER_ORDER = types;
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "createParticleGroup", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$createSnowstormParticleGroup(ParticleRenderType renderType, CallbackInfoReturnable<ParticleGroup<?>> cir) {
|
||||
if (renderType == ParticleMaterials.INSTANCE.getADD()
|
||||
|| renderType == ParticleMaterials.INSTANCE.getALPHA()
|
||||
|| renderType == ParticleMaterials.INSTANCE.getBLEND()
|
||||
|| renderType == ParticleMaterials.INSTANCE.getOPAQUE()) {
|
||||
cir.setReturnValue(new SnowstormParticleGroup((ParticleEngine) (Object) this, renderType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,12 +13,11 @@ import com.cobblemon.mod.common.CobblemonItems;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents;
|
||||
import com.cobblemon.mod.common.api.events.item.LeftoversCreatedEvent;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle;
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.air.HoverBehaviour;
|
||||
import com.cobblemon.mod.common.api.storage.party.PartyStore;
|
||||
import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore;
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
|
||||
import com.cobblemon.mod.common.duck.PlayerDuck;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
@@ -32,13 +31,12 @@ import com.cobblemon.mod.common.pokemon.Species;
|
||||
import com.cobblemon.mod.common.util.CompoundTagExtensionsKt;
|
||||
import com.cobblemon.mod.common.util.CompoundTagUtilities;
|
||||
import com.cobblemon.mod.common.util.DataKeys;
|
||||
import com.cobblemon.mod.common.util.ShoulderEntitySynchronizer;
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
@@ -51,10 +49,12 @@ import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.food.FoodProperties;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.storage.ValueInput;
|
||||
import net.minecraft.world.level.storage.ValueOutput;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Vector3f;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
@@ -66,34 +66,23 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mixin(Player.class)
|
||||
public abstract class PlayerMixin extends LivingEntity implements ScannableEntity, OrientationControllable, PlayerDuck, RidePassenger {
|
||||
@Unique
|
||||
private CompoundTag cobblemon$shoulderEntityLeft = new CompoundTag();
|
||||
@Unique
|
||||
private CompoundTag cobblemon$shoulderEntityRight = new CompoundTag();
|
||||
|
||||
@Unique
|
||||
private Vector3f cobblemon$driverInput;
|
||||
@Unique
|
||||
private Vector3f cobblemon$lastSentDriverInput;
|
||||
|
||||
@Shadow public abstract CompoundTag getShoulderEntityLeft();
|
||||
|
||||
@Shadow public abstract CompoundTag getShoulderEntityRight();
|
||||
|
||||
@Shadow public abstract void respawnEntityOnShoulder(CompoundTag entityNbt);
|
||||
|
||||
@Shadow public abstract void setShoulderEntityRight(CompoundTag entityNbt);
|
||||
|
||||
@Shadow public abstract void setShoulderEntityLeft(CompoundTag entityNbt);
|
||||
|
||||
@Shadow public abstract boolean isSpectator();
|
||||
|
||||
@Shadow public abstract boolean addItem(ItemStack stack);
|
||||
|
||||
@Shadow public abstract void displayClientMessage(Component message, boolean overlay);
|
||||
|
||||
@Shadow @Final private static Map<Pose, EntityDimensions> POSES;
|
||||
@Shadow @Final public static EntityDimensions STANDING_DIMENSIONS;
|
||||
@Shadow protected int jumpTriggerTime;
|
||||
@Unique private final OrientationController cobblemon$orientationController = new OrientationController(this);
|
||||
|
||||
@@ -107,71 +96,70 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
super(p_20966_, p_20967_);
|
||||
}
|
||||
|
||||
@Inject(method = "respawnEntityOnShoulder", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/EntityType;create(Lnet/minecraft/nbt/CompoundTag;Lnet/minecraft/world/level/Level;)Ljava/util/Optional;"), cancellable = true)
|
||||
private void cobblemon$removePokemon(CompoundTag nbt, CallbackInfo ci) {
|
||||
if (CompoundTagExtensionsKt.isPokemonEntity(nbt)) {
|
||||
final UUID uuid = CompoundTagUtilities.getPokemonID(nbt);
|
||||
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityRight())) {
|
||||
final UUID uuidRight = CompoundTagUtilities.getPokemonID(this.getShoulderEntityRight());
|
||||
if (uuid.equals(uuidRight)) {
|
||||
this.recallPokemon(uuidRight);
|
||||
this.setShoulderEntityRight(new CompoundTag());
|
||||
}
|
||||
}
|
||||
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityLeft())) {
|
||||
final UUID uuidLeft = CompoundTagUtilities.getPokemonID(this.getShoulderEntityLeft());
|
||||
if (uuid.equals(uuidLeft)) {
|
||||
this.recallPokemon(uuidLeft);
|
||||
this.setShoulderEntityLeft(new CompoundTag());
|
||||
}
|
||||
}
|
||||
ci.cancel();
|
||||
@Inject(method = "readAdditionalSaveData", at = @At("TAIL"))
|
||||
private void cobblemon$readShoulderData(ValueInput input, CallbackInfo ci) {
|
||||
input.read("ShoulderEntityLeft", CompoundTag.CODEC)
|
||||
.ifPresent(entityNbt -> this.cobblemon$setShoulderEntity(true, entityNbt, false));
|
||||
input.read("ShoulderEntityRight", CompoundTag.CODEC)
|
||||
.ifPresent(entityNbt -> this.cobblemon$setShoulderEntity(false, entityNbt, false));
|
||||
}
|
||||
|
||||
@Inject(method = "addAdditionalSaveData", at = @At("TAIL"))
|
||||
private void cobblemon$writeShoulderData(ValueOutput output, CallbackInfo ci) {
|
||||
CompoundTag leftShoulder = this.getShoulderEntityLeft();
|
||||
if (!leftShoulder.isEmpty()) {
|
||||
output.store("ShoulderEntityLeft", CompoundTag.CODEC, leftShoulder);
|
||||
}
|
||||
|
||||
CompoundTag rightShoulder = this.getShoulderEntityRight();
|
||||
if (!rightShoulder.isEmpty()) {
|
||||
output.store("ShoulderEntityRight", CompoundTag.CODEC, rightShoulder);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityDimensions getDefaultDimensions(Pose pose) {
|
||||
if (this.getVehicle() instanceof PokemonEntity) {
|
||||
return STANDING_DIMENSIONS;
|
||||
return super.getDefaultDimensions(Pose.STANDING);
|
||||
}
|
||||
return POSES.getOrDefault(pose, STANDING_DIMENSIONS);
|
||||
return super.getDefaultDimensions(pose);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "removeEntitiesOnShoulder",
|
||||
at = @At(
|
||||
value = "JUMP",
|
||||
opcode = Opcodes.IFGE,
|
||||
ordinal = 0,
|
||||
shift = At.Shift.AFTER
|
||||
),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$preventPokemonDropping(CallbackInfo ci) {
|
||||
// We want to allow both of these to forcefully remove the entities
|
||||
if (this.isSpectator() || this.isDeadOrDying())
|
||||
return;
|
||||
if (!CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityLeft())) {
|
||||
this.respawnEntityOnShoulder(this.getShoulderEntityLeft());
|
||||
this.setShoulderEntityLeft(new CompoundTag());
|
||||
}
|
||||
if (!CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityRight())) {
|
||||
this.respawnEntityOnShoulder(this.getShoulderEntityRight());
|
||||
this.setShoulderEntityRight(new CompoundTag());
|
||||
}
|
||||
ci.cancel();
|
||||
@Override
|
||||
public CompoundTag getShoulderEntityLeft() {
|
||||
return this.cobblemon$shoulderEntityLeft;
|
||||
}
|
||||
|
||||
private void recallPokemon(UUID uuid) {
|
||||
// We need to do this cause the Entity doesn't store a reference to its storage
|
||||
final PartyStore party = Cobblemon.INSTANCE.getStorage().getParty(this.getUUID(), this.registryAccess());
|
||||
for (Pokemon pokemon : party) {
|
||||
if (pokemon.getUuid().equals(uuid)) {
|
||||
pokemon.recall();
|
||||
}
|
||||
@Override
|
||||
public CompoundTag getShoulderEntityRight() {
|
||||
return this.cobblemon$shoulderEntityRight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShoulderEntityLeft(CompoundTag entityNbt) {
|
||||
this.cobblemon$setShoulderEntity(true, entityNbt, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShoulderEntityRight(CompoundTag entityNbt) {
|
||||
this.cobblemon$setShoulderEntity(false, entityNbt, true);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void cobblemon$setShoulderEntity(boolean isLeftShoulder, CompoundTag entityNbt, boolean shouldSync) {
|
||||
CompoundTag copied = entityNbt == null ? new CompoundTag() : entityNbt.copy();
|
||||
if (isLeftShoulder) {
|
||||
this.cobblemon$shoulderEntityLeft = copied;
|
||||
} else {
|
||||
this.cobblemon$shoulderEntityRight = copied;
|
||||
}
|
||||
|
||||
if (shouldSync && !this.level().isClientSide() && (Object)this instanceof ServerPlayer player) {
|
||||
ShoulderEntitySynchronizer.sync(player);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Redirect(
|
||||
method = "getDestroySpeed",
|
||||
at = @At(
|
||||
@@ -198,39 +186,11 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
return player.onGround();
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "eat",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/entity/player/Player;getFoodData()Lnet/minecraft/world/food/FoodData;",
|
||||
shift = At.Shift.AFTER
|
||||
)
|
||||
)
|
||||
public void onEatFood(Level world, ItemStack stack, FoodProperties foodComponent, CallbackInfoReturnable<ItemStack> cir) {
|
||||
if (!level().isClientSide) {
|
||||
if (stack.is(CobblemonItemTags.LEAVES_LEFTOVERS) && level().random.nextDouble() < Cobblemon.config.getAppleLeftoversChance()) {
|
||||
ItemStack leftovers = new ItemStack(CobblemonItems.LEFTOVERS);
|
||||
ServerPlayer player = Objects.requireNonNull(getServer()).getPlayerList().getPlayer(uuid);
|
||||
assert player != null;
|
||||
CobblemonEvents.LEFTOVERS_CREATED.postThen(
|
||||
new LeftoversCreatedEvent(player, leftovers),
|
||||
leftoversCreatedEvent -> null,
|
||||
leftoversCreatedEvent -> {
|
||||
if(!player.addItem(leftoversCreatedEvent.getLeftovers())) {
|
||||
var itemPos = player.getLookAngle().scale(0.5f).add(position());
|
||||
level().addFreshEntity(new ItemEntity(level(), itemPos.x(), itemPos.y(), itemPos.z(), leftoversCreatedEvent.getLeftovers()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "isInvulnerableTo", at = @At("HEAD"), cancellable = true)
|
||||
public void isInvulnerableTo(DamageSource source, CallbackInfoReturnable<Boolean> ci) {
|
||||
if (!level().isClientSide && (Object) this instanceof ServerPlayer player) {
|
||||
boolean invulnerableInBattle = this.level().getGameRules().getBoolean(CobblemonGameRules.BATTLE_INVULNERABILITY);
|
||||
public void isInvulnerableTo(net.minecraft.server.level.ServerLevel serverLevel, DamageSource source, CallbackInfoReturnable<Boolean> ci) {
|
||||
if ((Object) this instanceof ServerPlayer player) {
|
||||
boolean invulnerableInBattle = serverLevel.getGameRules().get(CobblemonGameRules.BATTLE_INVULNERABILITY);
|
||||
boolean inBattle = Cobblemon.INSTANCE.getBattleRegistry().getBattleByParticipatingPlayer(player) != null;
|
||||
if (invulnerableInBattle && inBattle) {
|
||||
ci.setReturnValue(true);
|
||||
@@ -240,34 +200,40 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
|
||||
@Override @Nullable
|
||||
public PokedexEntityData resolvePokemonScan() {
|
||||
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityRight())){
|
||||
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityRight())) {
|
||||
return getDataFromShoulderPokemon(this.getShoulderEntityRight());
|
||||
}
|
||||
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityLeft())){
|
||||
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityLeft())) {
|
||||
return getDataFromShoulderPokemon(this.getShoulderEntityLeft());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable @Unique
|
||||
@Nullable
|
||||
@Unique
|
||||
private PokedexEntityData getDataFromShoulderPokemon(CompoundTag shoulderTag) {
|
||||
Pokemon pokemon;
|
||||
if (level().isClientSide) {
|
||||
CompoundTag pokemonTag = shoulderTag.getCompound(DataKeys.POKEMON);
|
||||
if (level().isClientSide()) {
|
||||
CompoundTag pokemonTag = shoulderTag.getCompound(DataKeys.POKEMON).orElse(new CompoundTag());
|
||||
if (pokemonTag.isEmpty()) return null;
|
||||
Species species = PokemonSpecies.getByIdentifier(ResourceLocation.parse(pokemonTag.getString(DataKeys.POKEMON_SPECIES_IDENTIFIER)));
|
||||
String speciesId = pokemonTag.getString(DataKeys.POKEMON_SPECIES_IDENTIFIER).orElse("");
|
||||
if (speciesId.isEmpty()) return null;
|
||||
Species species = PokemonSpecies.getByIdentifier(Identifier.parse(speciesId));
|
||||
if (species == null) return null;
|
||||
String formId = pokemonTag.getString(DataKeys.POKEMON_FORM_ID);
|
||||
String formId = pokemonTag.getString(DataKeys.POKEMON_FORM_ID).orElse("");
|
||||
FormData form = species.getStandardForm();
|
||||
List<FormData> formList = species.getForms().stream().filter(it -> it.formOnlyShowdownId().equals(formId)).toList();
|
||||
if (!formList.isEmpty()) form = formList.getFirst();
|
||||
if (form == null) return null;
|
||||
String genderString = pokemonTag.getString(DataKeys.POKEMON_GENDER);
|
||||
String genderString = pokemonTag.getString(DataKeys.POKEMON_GENDER).orElse("");
|
||||
if (genderString.isEmpty()) return null;
|
||||
Gender gender = Gender.valueOf(genderString);
|
||||
boolean shiny = pokemonTag.getBoolean(DataKeys.POKEMON_SHINY);
|
||||
int level = pokemonTag.getInt(DataKeys.POKEMON_LEVEL);
|
||||
Set<String> aspects = shoulderTag.getList(DataKeys.SHOULDER_ASPECTS, Tag.TAG_STRING).stream().map(Tag::getAsString).collect(Collectors.toSet());
|
||||
boolean shiny = pokemonTag.getBoolean(DataKeys.POKEMON_SHINY).orElse(false);
|
||||
int level = pokemonTag.getInt(DataKeys.POKEMON_LEVEL).orElse(0);
|
||||
Set<String> aspects = new HashSet<>();
|
||||
for (var tag : shoulderTag.getList(DataKeys.SHOULDER_ASPECTS).orElse(new ListTag())) {
|
||||
tag.asString().ifPresent(aspects::add);
|
||||
}
|
||||
|
||||
pokemon = new Pokemon();
|
||||
pokemon.setSpecies(species);
|
||||
@@ -277,8 +243,8 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
pokemon.setLevel(level);
|
||||
pokemon.setForcedAspects(aspects);
|
||||
} else {
|
||||
PlayerPartyStore party = Cobblemon.INSTANCE.getStorage().getParty(this.getUUID(), this.registryAccess());
|
||||
pokemon = party.get(shoulderTag.getUUID(DataKeys.SHOULDER_UUID));
|
||||
PartyStore party = Cobblemon.INSTANCE.getStorage().getParty(this.getUUID(), this.registryAccess());
|
||||
pokemon = party.get(CompoundTagExtensionsKt.getUUID(shoulderTag, DataKeys.SHOULDER_UUID));
|
||||
}
|
||||
return (pokemon == null) ? null : new PokedexEntityData(pokemon, null);
|
||||
}
|
||||
@@ -288,21 +254,6 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void absMoveTo(double x, double y, double z, float yaw, float pitch) {
|
||||
if (cobblemon$orientationController.getActive()) {
|
||||
this.absMoveTo(x, y, z);
|
||||
this.setYRot(yaw % 360.0f);
|
||||
this.setXRot(pitch % 360.0f);
|
||||
this.yRotO = this.getYRot();
|
||||
this.xRotO = this.getXRot();
|
||||
}
|
||||
else {
|
||||
this.absMoveTo(x, y, z);
|
||||
this.absRotateTo(yaw, pitch);
|
||||
}
|
||||
}
|
||||
|
||||
@WrapOperation(
|
||||
method = "rideTick()V",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;wantsToStopRiding()Z")
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonRecipeBookTypes;
|
||||
import net.minecraft.stats.RecipeBookSettings;
|
||||
import net.minecraft.world.inventory.RecipeBookType;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
@Mixin(RecipeBookSettings.class)
|
||||
public class RecipeBookSettingsMixin {
|
||||
@Unique
|
||||
private RecipeBookSettings.TypeSettings cobblemon$cookingPot = new RecipeBookSettings.TypeSettings(false, false);
|
||||
|
||||
@Inject(method = "getSettings", at = @At("HEAD"), cancellable = true)
|
||||
public void getSettings(RecipeBookType type, CallbackInfoReturnable<RecipeBookSettings.TypeSettings> cir) {
|
||||
if (type == CobblemonRecipeBookTypes.INSTANCE.getCOOKING_POT()) {
|
||||
cir.setReturnValue(cobblemon$cookingPot);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "updateSettings", at = @At("HEAD"), cancellable = true)
|
||||
private void updateSetting(RecipeBookType recipeBookType, UnaryOperator<RecipeBookSettings.TypeSettings> operator, CallbackInfo ci) {
|
||||
if (recipeBookType == CobblemonRecipeBookTypes.INSTANCE.getCOOKING_POT()) {
|
||||
cobblemon$cookingPot = operator.apply(cobblemon$cookingPot);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-3
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.fabric.mixin;
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonRecipeBookTypes;
|
||||
import net.minecraft.world.inventory.RecipeBookType;
|
||||
@@ -41,8 +41,6 @@ public class RecipeBookTypeMixin {
|
||||
)
|
||||
private static void cobblemon$addRecipeBookType(CallbackInfo ci) {
|
||||
ArrayList<RecipeBookType> types = new ArrayList<>(List.of($VALUES));
|
||||
// if you change or add any of these, neoforge uses a separate mechanism
|
||||
// check enumextensions.json and `CobblemonEnumExtensions`
|
||||
types.add(cobblemon$createBookType(CobblemonRecipeBookTypes.COOKING_POT_NAME, $VALUES.length));
|
||||
$VALUES = types.toArray(RecipeBookType[]::new);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonRecipePropertySets;
|
||||
import com.cobblemon.mod.common.item.crafting.CookingPotRecipeBase;
|
||||
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.item.crafting.Ingredient;
|
||||
import net.minecraft.world.item.crafting.RecipeManager;
|
||||
import net.minecraft.world.item.crafting.RecipePropertySet;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@Mixin(RecipeManager.class)
|
||||
public abstract class RecipeManagerMixin {
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private static Map<ResourceKey<RecipePropertySet>, RecipeManager.IngredientExtractor> RECIPE_PROPERTY_SETS;
|
||||
|
||||
@WrapOperation(method = "<clinit>", at = @At(value = "INVOKE", target = "Ljava/util/Map;of(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/util/Map;"))
|
||||
private static Map poggers(Object k1, Object v1,
|
||||
Object k2, Object v2,
|
||||
Object k3, Object v3,
|
||||
Object k4, Object v4,
|
||||
Object k5, Object v5,
|
||||
Object k6, Object v6,
|
||||
Object k7, Object v7,
|
||||
Operation<Map> original) {
|
||||
return new HashMap(original.call(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7));
|
||||
}
|
||||
|
||||
@Inject(method = "<clinit>", at = @At("TAIL"))
|
||||
private static void cobblemon$addPropertySets(CallbackInfo ci) {
|
||||
RECIPE_PROPERTY_SETS.put(CobblemonRecipePropertySets.INSTANCE.getBREWING_BOTTLE(), recipe -> {
|
||||
if (recipe instanceof BrewingStandRecipe brew) {
|
||||
return Optional.of(brew.getBottle());
|
||||
}
|
||||
return Optional.empty();
|
||||
});
|
||||
|
||||
RECIPE_PROPERTY_SETS.put(CobblemonRecipePropertySets.INSTANCE.getBREWING_INPUT(), recipe -> {
|
||||
if (recipe instanceof BrewingStandRecipe brew) {
|
||||
return Optional.of(brew.getInput());
|
||||
}
|
||||
return Optional.empty();
|
||||
});
|
||||
|
||||
RECIPE_PROPERTY_SETS.put(CobblemonRecipePropertySets.INSTANCE.getCOOKING_POT_FLAVOUR_PROCESSOR(), recipe -> {
|
||||
if (recipe instanceof CookingPotRecipeBase cooking && cooking.getSeasoningProcessors().stream().anyMatch(x -> x.getType().equals("flavour"))) {
|
||||
return Optional.of(Ingredient.of(cooking.getResult().item().value()));
|
||||
}
|
||||
return Optional.empty();
|
||||
});
|
||||
|
||||
RECIPE_PROPERTY_SETS.put(CobblemonRecipePropertySets.INSTANCE.getCOOKING_POT_FOOD_PROCESSOR(), recipe -> {
|
||||
if (recipe instanceof CookingPotRecipeBase cooking && cooking.getSeasoningProcessors().stream().anyMatch(x -> x.getType().equals("food"))) {
|
||||
return Optional.of(Ingredient.of(cooking.getResult().item().value()));
|
||||
}
|
||||
return Optional.empty();
|
||||
});
|
||||
|
||||
RECIPE_PROPERTY_SETS.put(CobblemonRecipePropertySets.INSTANCE.getCOOKING_POT_MOB_EFFECTS_PROCESSOR(), recipe -> {
|
||||
if (recipe instanceof CookingPotRecipeBase cooking && cooking.getSeasoningProcessors().stream().anyMatch(x -> x.getType().equals("mob_effects"))) {
|
||||
return Optional.of(Ingredient.of(cooking.getResult().item().value()));
|
||||
}
|
||||
return Optional.empty();
|
||||
});
|
||||
|
||||
RECIPE_PROPERTY_SETS.put(CobblemonRecipePropertySets.INSTANCE.getCOOKING_POT_SPAWN_BAIT_PROCESSOR(), recipe -> {
|
||||
if (recipe instanceof CookingPotRecipeBase cooking && cooking.getSeasoningProcessors().stream().anyMatch(x -> x.getType().equals("spawn_bait"))) {
|
||||
return Optional.of(Ingredient.of(cooking.getResult().item().value()));
|
||||
}
|
||||
return Optional.empty();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -19,16 +19,17 @@ import com.cobblemon.mod.common.mixin.accessor.TrackedEntityAccessor;
|
||||
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateDriverInputPacket;
|
||||
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateOrientationPacket;
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.ClientboundUpdateRidingStatePacket;
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.ClientboundSeatAssignmentPacket;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.ServerEntity;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.network.ServerPlayerConnection;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Vector3f;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
@@ -39,16 +40,12 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Mixin(ServerEntity.class)
|
||||
public abstract class ServerEntityMixin {
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private Consumer<Packet<?>> broadcast;
|
||||
@Shadow
|
||||
@Final
|
||||
private Entity entity;
|
||||
@@ -56,15 +53,12 @@ public abstract class ServerEntityMixin {
|
||||
private Matrix3f cobblemon$lastSentOrientation;
|
||||
@Unique
|
||||
private boolean cobblemon$lastSentActive;
|
||||
@Unique
|
||||
private List<Entity> cobblemon$lastSeatPassengers = List.of();
|
||||
|
||||
@Inject(method = "sendChanges", at = @At("TAIL"))
|
||||
private void cobblemon$sendChanges(CallbackInfo ci) {
|
||||
cobblemon$sendOrientationChanges();
|
||||
cobblemon$sendRidingStateChanges();
|
||||
cobblemon$sendDriverInput();
|
||||
cobblemon$sendOccupiedSeatsChange();
|
||||
}
|
||||
|
||||
private void cobblemon$sendRidingStateChanges() {
|
||||
@@ -107,24 +101,6 @@ public abstract class ServerEntityMixin {
|
||||
cobblemon$broadcast(new ClientboundUpdateDriverInputPacket(driverInput, entity.getId()));
|
||||
}
|
||||
|
||||
private void cobblemon$sendOccupiedSeatsChange() {
|
||||
if (!(this.entity instanceof PokemonEntity pokemon)) return;
|
||||
|
||||
List<Entity> currentPassengers = pokemon.getPassengers();
|
||||
if (currentPassengers.equals(cobblemon$lastSeatPassengers)) return;
|
||||
cobblemon$lastSeatPassengers = List.copyOf(currentPassengers);
|
||||
|
||||
pokemon.getOccupiedSeats().forEach((seat, passenger) -> {
|
||||
if (seat.getLocator() == null) return;
|
||||
if (passenger == null) return;
|
||||
cobblemon$broadcast(new ClientboundSeatAssignmentPacket(
|
||||
passenger.getId(),
|
||||
pokemon.getId(),
|
||||
seat.getLocator()
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
private void cobblemon$broadcast(NetworkPacket<?> packet) {
|
||||
if (!(entity.level() instanceof ServerLevel level)) return;
|
||||
ChunkMap chunkMap = level.getChunkSource().chunkMap;
|
||||
@@ -139,4 +115,5 @@ public abstract class ServerEntityMixin {
|
||||
CobblemonNetwork.INSTANCE.sendPacketToPlayer(player, packet);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,14 +30,14 @@ public abstract class ServerLevelMixin {
|
||||
final ServerLevel serverLevel = (ServerLevel) (Object) this;
|
||||
if (ci.getReturnValue().isEmpty()) {
|
||||
// Search for Pokemon with the ability Lightning Rod and redirect to them
|
||||
AABB aABB = AABB.encapsulatingFullBlocks(blockPos, new BlockPos(blockPos.atY(serverLevel.getMaxBuildHeight()))).inflate(64.0);
|
||||
AABB aABB = AABB.encapsulatingFullBlocks(blockPos, new BlockPos(blockPos.atY(serverLevel.getMaxY() + 1))).inflate(64.0);
|
||||
List<LivingEntity> list = serverLevel.getEntitiesOfClass(LivingEntity.class, aABB, (livingEntity) -> livingEntity != null
|
||||
&& livingEntity.isAlive()
|
||||
&& livingEntity instanceof PokemonEntity
|
||||
&& ((PokemonEntity) livingEntity).getBeamMode() == 0
|
||||
&& ((PokemonEntity) livingEntity).getPokemon().getAbility().getName().equals("lightningrod"));
|
||||
if (!list.isEmpty()) {
|
||||
ci.setReturnValue(Optional.of((list.get(serverLevel.random.nextInt(list.size()))).blockPosition()));
|
||||
ci.setReturnValue(Optional.of((list.get(serverLevel.getRandom().nextInt(list.size()))).blockPosition()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,29 +16,43 @@ import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner;
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory;
|
||||
import com.cobblemon.mod.common.api.stats.CobblemonStats;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.util.CompoundTagUtilities;
|
||||
import com.cobblemon.mod.common.util.ShoulderEntitySynchronizer;
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ServerPlayer.class)
|
||||
public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
|
||||
@Shadow
|
||||
public abstract ServerLevel serverLevel();
|
||||
|
||||
@Shadow public abstract CompoundTag getShoulderEntityLeft();
|
||||
|
||||
@Shadow public abstract CompoundTag getShoulderEntityRight();
|
||||
|
||||
@Shadow public abstract void respawnEntityOnShoulder(CompoundTag entityNbt);
|
||||
|
||||
@Shadow public abstract void setShoulderEntityRight(CompoundTag entityNbt);
|
||||
|
||||
@Shadow public abstract void setShoulderEntityLeft(CompoundTag entityNbt);
|
||||
|
||||
@Unique
|
||||
public PlayerSpawner cobblemon$spawner;
|
||||
|
||||
@Shadow
|
||||
private long timeEntitySatOnShoulder;
|
||||
|
||||
@Override
|
||||
public PlayerSpawner getPlayerSpawner() {
|
||||
ServerPlayer player = (ServerPlayer)(Object)this;
|
||||
@@ -55,21 +69,60 @@ public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
|
||||
|
||||
@Inject(method = "tick", at = @At("TAIL"))
|
||||
private void cobblemon$tickSpawner(CallbackInfo ci) {
|
||||
ServerPlayer player = (ServerPlayer)(Object)this;
|
||||
if (!Cobblemon.config.getEnableSpawning()) {
|
||||
return;
|
||||
} else if (!serverLevel().getGameRules().getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING)) {
|
||||
} else if (!player.level().getGameRules().get(CobblemonGameRules.DO_POKEMON_SPAWNING)) {
|
||||
return;
|
||||
}
|
||||
getPlayerSpawner().tick();
|
||||
}
|
||||
|
||||
@Inject(method = "removeEntitiesOnShoulder", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$preventPokemonDropping(CallbackInfo ci) {
|
||||
ServerPlayer player = (ServerPlayer)(Object)this;
|
||||
if (player.isSpectator() || player.isDeadOrDying()) {
|
||||
return;
|
||||
}
|
||||
|
||||
long gameTime = player.level().getGameTime();
|
||||
if (this.timeEntitySatOnShoulder + 20L >= gameTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean changed = false;
|
||||
CompoundTag leftShoulder = player.getShoulderEntityLeft();
|
||||
if (!leftShoulder.isEmpty() && !CompoundTagUtilities.isShoulderPokemon(leftShoulder)) {
|
||||
respawnEntityOnShoulder(leftShoulder);
|
||||
setShoulderEntityLeft(new CompoundTag());
|
||||
changed = true;
|
||||
}
|
||||
|
||||
CompoundTag rightShoulder = player.getShoulderEntityRight();
|
||||
if (!rightShoulder.isEmpty() && !CompoundTagUtilities.isShoulderPokemon(rightShoulder)) {
|
||||
respawnEntityOnShoulder(rightShoulder);
|
||||
setShoulderEntityRight(new CompoundTag());
|
||||
changed = true;
|
||||
}
|
||||
|
||||
this.timeEntitySatOnShoulder = gameTime;
|
||||
if (changed) {
|
||||
ShoulderEntitySynchronizer.sync(player);
|
||||
}
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
private void cobblemon$updateOrientationControllerRideTick(CallbackInfo ci) {
|
||||
ServerPlayer player = (ServerPlayer)(Object)this;
|
||||
Entity vehicle = player.getVehicle();
|
||||
if (!(vehicle instanceof OrientationControllable controllableVehicle)) return;
|
||||
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation(vehicle);
|
||||
controllableVehicle.getOrientationController().setActive(shouldUseCustomOrientation);
|
||||
var controller = controllableVehicle.getOrientationController();
|
||||
controller.setActive(shouldUseCustomOrientation);
|
||||
if (shouldUseCustomOrientation && controller.getOrientation() == null) {
|
||||
controller.updateOrientation(matrix -> matrix);
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
@@ -81,16 +134,9 @@ public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
|
||||
});
|
||||
}
|
||||
|
||||
@Inject(method = "stopRiding", at = @At("HEAD"))
|
||||
public void cobblemon$resetOrientationOnDismount(CallbackInfo ci) {
|
||||
ServerPlayer player = (ServerPlayer)(Object)this;
|
||||
if (!(player.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
|
||||
controllableVehicle.getOrientationController().setActive(false);
|
||||
}
|
||||
|
||||
//TODO: Switch to sending out on load instead of preventing saving
|
||||
@ModifyExpressionValue(method = "addAdditionalSaveData", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;hasExactlyOnePlayerPassenger()Z"))
|
||||
private boolean cobblemon$cancelSavingPokemonMounts(boolean original, @Local(ordinal=0) Entity entity) {
|
||||
@ModifyExpressionValue(method = "saveParentVehicle", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;hasExactlyOnePlayerPassenger()Z"))
|
||||
private boolean cobblemon$cancelSavingPokemonMounts(boolean original, @Local(name = "rootVehicle") Entity entity) {
|
||||
return original && !(entity instanceof PokemonEntity);
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -13,6 +13,7 @@ import kotlin.Unit;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.dispenser.ShearsDispenseItemBehavior;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
@@ -24,10 +25,10 @@ public abstract class ShearsDispenserBehaviorMixin {
|
||||
|
||||
// This exists, so we can execute our custom interaction only if no one redirected shears interactions to overwrite the vanilla ones.
|
||||
@Inject(method = "tryShearBeehive", at = @At("HEAD"), cancellable = true)
|
||||
private static void cobblemon$tryApricornHarvest(ServerLevel world, BlockPos pos, CallbackInfoReturnable<Boolean> cir) {
|
||||
final BlockState state = world.getBlockState(pos);
|
||||
private static void cobblemon$tryApricornHarvest(ServerLevel serverLevel, ItemStack itemStack, BlockPos blockPos, CallbackInfoReturnable<Boolean> cir) {
|
||||
final BlockState state = serverLevel.getBlockState(blockPos);
|
||||
if (state.getBlock() instanceof ShearableBlock shearableBlock) {
|
||||
cir.setReturnValue(shearableBlock.attemptShear(world, state, pos, () -> Unit.INSTANCE));
|
||||
cir.setReturnValue(shearableBlock.attemptShear(serverLevel, state, blockPos, () -> Unit.INSTANCE));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
import static com.cobblemon.mod.common.datafixer.CobblemonSchemas.VERSION_KEY;
|
||||
|
||||
import com.cobblemon.mod.common.datafixer.CobblemonSchemas;
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.util.datafix.DataFixTypes;
|
||||
import net.minecraft.world.level.chunk.storage.SimpleRegionStorage;
|
||||
import org.spongepowered.asm.mixin.Debug;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
@Mixin(SimpleRegionStorage.class)
|
||||
public class SimpleRegionStorageMixin {
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private DataFixTypes dataFixType;
|
||||
//Modifies the NBT returned by the vanilla upgradeChunkTag to also incorporate cobblemon fixup stuff
|
||||
@ModifyExpressionValue(
|
||||
method = "upgradeChunkTag(Lnet/minecraft/nbt/CompoundTag;ILnet/minecraft/nbt/CompoundTag;I)Lnet/minecraft/nbt/CompoundTag;",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/util/datafix/DataFixTypes;update(Lcom/mojang/datafixers/DataFixer;Lnet/minecraft/nbt/CompoundTag;II)Lnet/minecraft/nbt/CompoundTag;"
|
||||
)
|
||||
)
|
||||
public CompoundTag cobblemon$doChunkFix(
|
||||
CompoundTag vanillaFixed
|
||||
) {
|
||||
int curVersion = vanillaFixed.getIntOr(VERSION_KEY, 0);
|
||||
return vanillaFixed; //TODO FIGURE OUT WHAT THE HECK IS GOING ON HERE
|
||||
//return this.dataFixType.update(CobblemonSchemas.getDATA_FIXER(), vanillaFixed, curVersion, CobblemonSchemas.DATA_VERSION);
|
||||
}
|
||||
}
|
||||
@@ -21,9 +21,8 @@ import net.minecraft.client.resources.sounds.SoundInstance;
|
||||
import net.minecraft.client.resources.sounds.TickableSoundInstance;
|
||||
import net.minecraft.client.sounds.ChannelAccess;
|
||||
import net.minecraft.client.sounds.SoundEngine;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
@@ -33,7 +32,6 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
import java.util.Iterator;
|
||||
@@ -71,56 +69,45 @@ public abstract class SoundEngineMixin implements SoundEngineDuck {
|
||||
|
||||
/** Resumes the SoundInstance(s) queried by id and/or category. */
|
||||
@Override
|
||||
public void resumeSounds(@Nullable ResourceLocation id, @Nullable SoundSource category) {
|
||||
public void resumeSounds(@Nullable Identifier id, @Nullable SoundSource category) {
|
||||
if (category != null) {
|
||||
this.instanceBySource.get(category).forEach((sound) -> {
|
||||
if (id == null || sound.getLocation().equals(id)) resume(sound);
|
||||
if (id == null || sound.getIdentifier().equals(id)) resume(sound);
|
||||
});
|
||||
} else if (id == null) {
|
||||
this.instanceToChannel.keySet().forEach(this::resume);
|
||||
} else {
|
||||
this.instanceToChannel.keySet().forEach(sound -> {
|
||||
if (sound.getLocation().equals(id)) resume(sound);
|
||||
if (sound.getIdentifier().equals(id)) resume(sound);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Pauses the SoundInstances queried by id and/or category. */
|
||||
@Override
|
||||
public void pauseSounds(@Nullable ResourceLocation id, @Nullable SoundSource category) {
|
||||
public void pauseSounds(@Nullable Identifier id, @Nullable SoundSource category) {
|
||||
if (category != null) {
|
||||
this.instanceBySource.get(category).forEach((sound) -> {
|
||||
if (id == null || sound.getLocation().equals(id)) pause(sound);
|
||||
if (id == null || sound.getIdentifier().equals(id)) pause(sound);
|
||||
});
|
||||
} else if (id == null) {
|
||||
this.instanceToChannel.keySet().forEach(this::pause);
|
||||
} else {
|
||||
this.instanceToChannel.keySet().forEach(sound -> {
|
||||
if (sound.getLocation().equals(id)) pause(sound);
|
||||
if (sound.getIdentifier().equals(id)) pause(sound);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Allows stopping all SoundInstances that belong to a queried category. */
|
||||
@Inject(method = "stop(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/sounds/SoundSource;)V", at = @At("HEAD"), cancellable = true)
|
||||
public void stopSounds(@Nullable ResourceLocation id, @Nullable SoundSource category, CallbackInfo cb) {
|
||||
@Inject(method = "stop(Lnet/minecraft/resources/Identifier;Lnet/minecraft/sounds/SoundSource;)V", at = @At("HEAD"), cancellable = true)
|
||||
public void stopSounds(@Nullable Identifier id, @Nullable SoundSource category, CallbackInfo cb) {
|
||||
if (id == null && category != null) {
|
||||
this.instanceBySource.get(category).forEach(this::stop);
|
||||
cb.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TM Shelf can intentionally push note-block pitches above vanilla's 2.0f ceiling for octave-up playback.
|
||||
* Keep vanilla clamping for all other sounds.
|
||||
*/
|
||||
@Inject(method = "calculatePitch", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$allowExtendedNoteblockPitch(SoundInstance sound, CallbackInfoReturnable<Float> cir) {
|
||||
if (sound.getLocation().getPath().startsWith("block.note_block.")) {
|
||||
cir.setReturnValue(Mth.clamp(sound.getPitch(), 0.5F, 4.0F));
|
||||
}
|
||||
}
|
||||
|
||||
/** Different behavior for resuming SoundInstances while a BattleMusicInstance is being played. We do not want to resume filtered sounds. */
|
||||
@Inject(method = "resume()V", at = @At("HEAD"), cancellable = true)
|
||||
public void resume(CallbackInfo cb) {
|
||||
|
||||
@@ -17,7 +17,7 @@ import net.minecraft.client.resources.sounds.SoundInstance;
|
||||
import net.minecraft.client.resources.sounds.UnderwaterAmbientSoundInstances;
|
||||
import net.minecraft.client.sounds.SoundEngine;
|
||||
import net.minecraft.client.sounds.SoundManager;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
@@ -26,6 +26,7 @@ import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(SoundManager.class)
|
||||
public abstract class SoundManagerMixin implements SoundManagerDuck {
|
||||
@@ -55,20 +56,20 @@ public abstract class SoundManagerMixin implements SoundManagerDuck {
|
||||
|
||||
/** Pauses the queried SoundInstance(s). If id is null, will pause all sounds belonging to the SoundCategory. */
|
||||
@Override
|
||||
public void pauseSounds(@Nullable ResourceLocation id, @Nullable SoundSource category) {
|
||||
public void pauseSounds(@Nullable Identifier id, @Nullable SoundSource category) {
|
||||
((SoundEngineDuck)soundEngine).pauseSounds(id, category);
|
||||
}
|
||||
|
||||
/** Resumes the queried SoundInstance(s). If id is null, will resume all sounds belonging to the SoundCategory. */
|
||||
@Override
|
||||
public void resumeSounds(@Nullable ResourceLocation id, @Nullable SoundSource category) {
|
||||
public void resumeSounds(@Nullable Identifier id, @Nullable SoundSource category) {
|
||||
((SoundEngineDuck)soundEngine).resumeSounds(id, category);
|
||||
}
|
||||
|
||||
/** Blocks filtered sounds from being played while a BattleMusicInstance is in progress. */
|
||||
@Inject(method = "play(Lnet/minecraft/client/resources/sounds/SoundInstance;)V", at = @At("HEAD"), cancellable = true)
|
||||
public void playStart(SoundInstance sound, CallbackInfo cb) {
|
||||
if (filterCondition(sound)) cb.cancel();
|
||||
@Inject(method = "play", at = @At("HEAD"), cancellable = true)
|
||||
public void playStart(SoundInstance soundInstance, CallbackInfoReturnable<SoundEngine.PlayResult> cir) {
|
||||
if (filterCondition(soundInstance)) cir.cancel();
|
||||
}
|
||||
|
||||
@Inject(method = "playDelayed(Lnet/minecraft/client/resources/sounds/SoundInstance;I)V", at = @At("HEAD"), cancellable = true)
|
||||
@@ -77,14 +78,14 @@ public abstract class SoundManagerMixin implements SoundManagerDuck {
|
||||
}
|
||||
|
||||
/** Pauses ambient loops while a BattleMusicInstance is in progress. */
|
||||
@Inject(method = "play(Lnet/minecraft/client/resources/sounds/SoundInstance;)V", at = @At("TAIL"))
|
||||
public void playEnd(SoundInstance sound, CallbackInfo cb) {
|
||||
if (ambientLoopCondition(sound)) this.pauseSounds(sound.getLocation(), SoundSource.AMBIENT);
|
||||
@Inject(method = "play", at = @At("TAIL"))
|
||||
public void playEnd(SoundInstance soundInstance, CallbackInfoReturnable<SoundEngine.PlayResult> cir) {
|
||||
if (ambientLoopCondition(soundInstance)) this.pauseSounds(soundInstance.getIdentifier(), SoundSource.AMBIENT);
|
||||
}
|
||||
|
||||
@Inject(method = "playDelayed(Lnet/minecraft/client/resources/sounds/SoundInstance;I)V", at = @At("TAIL"))
|
||||
public void playEnd(SoundInstance sound, int delay, CallbackInfo cb) {
|
||||
if (ambientLoopCondition(sound)) this.pauseSounds(sound.getLocation(), SoundSource.AMBIENT);
|
||||
if (ambientLoopCondition(sound)) this.pauseSounds(sound.getIdentifier(), SoundSource.AMBIENT);
|
||||
}
|
||||
|
||||
/** Clears tracked sounds on the client when disconnected. */
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.world.CobblemonStructureIDs;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.LevelHeightAccessor;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.biome.BiomeSource;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
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<Identifier> 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(Holder<Structure> structure, ResourceKey<Level> levelKey, RegistryAccess registryAccess, ChunkGenerator chunkGenerator, BiomeSource biomeSource,
|
||||
RandomState randomState, StructureTemplateManager structureTemplateManager, long seed,
|
||||
ChunkPos chunkPos, int references, LevelHeightAccessor heightAccessor,
|
||||
Predicate<Holder<Biome>> validBiome,
|
||||
CallbackInfoReturnable<StructureStart> cir,
|
||||
@Local StructureStart structureStart) {
|
||||
Identifier structureKey = structure.unwrapKey().map(ResourceKey::identifier).orElse(null);
|
||||
if(!RESTRICTED_STRUCTURES.contains(structureKey)) {
|
||||
return;
|
||||
}
|
||||
for (StructurePiece piece : structureStart.getPieces()) {
|
||||
if (piece.getBoundingBox().minY() < chunkGenerator.getSeaLevel()) {
|
||||
cir.setReturnValue(StructureStart.INVALID_START);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,4 +29,4 @@ public interface StructurePoolAccessor {
|
||||
|
||||
@Accessor("templates")
|
||||
ObjectArrayList<StructurePoolElement> getElements();
|
||||
}
|
||||
}
|
||||
|
||||
+11
-11
@@ -11,7 +11,7 @@ package com.cobblemon.mod.common.mixin;
|
||||
import com.cobblemon.mod.common.world.CobblemonStructureIDs;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.LevelHeightAccessor;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
@@ -38,7 +38,7 @@ public abstract class StructurePoolGeneratorMixin {
|
||||
Map<String, Integer> generatedStructureGroupCounts;
|
||||
|
||||
private static final Map<String, Integer> structureMaxes;
|
||||
private static final Map<ResourceLocation, Set<String>> structureGroups = new HashMap<>();
|
||||
private static final Map<Identifier, Set<String>> structureGroups = new HashMap<>();
|
||||
static {
|
||||
String pokecenter = "pokecenter";
|
||||
String berry = "berry_farm";
|
||||
@@ -73,11 +73,11 @@ public abstract class StructurePoolGeneratorMixin {
|
||||
structureMaxes = Collections.unmodifiableMap(aMap);
|
||||
}
|
||||
|
||||
public Set<String> getGroups(ResourceLocation structureIdentifier) {
|
||||
public Set<String> getGroups(Identifier structureIdentifier) {
|
||||
return structureGroups.getOrDefault(structureIdentifier, Set.of());
|
||||
}
|
||||
|
||||
public boolean hasReachedMaximum(ResourceLocation structureIdentifier) {
|
||||
public boolean hasReachedMaximum(Identifier structureIdentifier) {
|
||||
Set<String> groups = getGroups(structureIdentifier);
|
||||
for (String group : groups) {
|
||||
int count = generatedStructureGroupCounts.getOrDefault(group, 0);
|
||||
@@ -89,7 +89,7 @@ public abstract class StructurePoolGeneratorMixin {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void incrementStructureCount(ResourceLocation structureIdentifier) {
|
||||
public void incrementStructureCount(Identifier structureIdentifier) {
|
||||
Set<String> groups = getGroups(structureIdentifier);
|
||||
for (String group : groups) {
|
||||
generatedStructureGroupCounts.put(group, generatedStructureGroupCounts.getOrDefault(group, 0) + 1);
|
||||
@@ -107,7 +107,7 @@ public abstract class StructurePoolGeneratorMixin {
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
StructurePoolElement structure = iterator.next();
|
||||
ResourceLocation structurePieceLocationKey = getCobblemonOnlyLocation(structure);
|
||||
Identifier structurePieceLocationKey = getCobblemonOnlyLocation(structure);
|
||||
if (structurePieceLocationKey == null) {
|
||||
reducedList.add(structure);
|
||||
continue;
|
||||
@@ -134,14 +134,14 @@ public abstract class StructurePoolGeneratorMixin {
|
||||
CallbackInfo ci,
|
||||
@Local(ordinal = 1) StructurePoolElement structurePoolElement
|
||||
) {
|
||||
ResourceLocation structureLocationKey = getCobblemonOnlyLocation(structurePoolElement);
|
||||
Identifier structureLocationKey = getCobblemonOnlyLocation(structurePoolElement);
|
||||
if (structureLocationKey != null) {
|
||||
incrementStructureCount(structureLocationKey);
|
||||
}
|
||||
}
|
||||
|
||||
private static ResourceLocation getCobblemonOnlyLocation(StructurePoolElement structurePoolElement) {
|
||||
ResourceLocation location = getLocationIfAvailable(structurePoolElement);
|
||||
private static Identifier getCobblemonOnlyLocation(StructurePoolElement structurePoolElement) {
|
||||
Identifier location = getLocationIfAvailable(structurePoolElement);
|
||||
if (location == null) return null;
|
||||
|
||||
if (!location.getNamespace().equals("cobblemon")) return null;
|
||||
@@ -149,7 +149,7 @@ public abstract class StructurePoolGeneratorMixin {
|
||||
return location;
|
||||
}
|
||||
|
||||
private static ResourceLocation getLocationIfAvailable(StructurePoolElement structurePoolElement) {
|
||||
private static Identifier getLocationIfAvailable(StructurePoolElement structurePoolElement) {
|
||||
if (structurePoolElement instanceof LegacySinglePoolElement legacySinglePoolElement) {
|
||||
if (legacySinglePoolElement.template.left().isEmpty()) return null;
|
||||
|
||||
@@ -162,4 +162,4 @@ public abstract class StructurePoolGeneratorMixin {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.bedrockk.molang.runtime.value.DoubleValue;
|
||||
import com.cobblemon.mod.common.entity.MoLangScriptingEntity;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.InsideBlockEffectApplier;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.SweetBerryBushBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
@@ -25,7 +26,15 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
public abstract class SweetBerryBushBlockMixin {
|
||||
|
||||
@Inject(method = "entityInside", at = @At(value = "HEAD"), cancellable = true)
|
||||
private void cobblemon$entityInside(BlockState state, Level level, BlockPos pos, Entity entity, CallbackInfo callbackInfo) {
|
||||
private void cobblemon$entityInside(
|
||||
BlockState state,
|
||||
Level level,
|
||||
BlockPos pos,
|
||||
Entity entity,
|
||||
InsideBlockEffectApplier effectApplier,
|
||||
boolean moved,
|
||||
CallbackInfo callbackInfo
|
||||
) {
|
||||
if (entity instanceof MoLangScriptingEntity) {
|
||||
if (((MoLangScriptingEntity) entity).getConfig().getMap().getOrDefault("immune_to_sweet_berry_bush_block", DoubleValue.ZERO).asDouble() == 1.0) {
|
||||
callbackInfo.cancel();
|
||||
|
||||
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.ai.targeting.TargetingConditions;
|
||||
@@ -23,11 +24,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
public class TargetingConditionsMixin {
|
||||
|
||||
@Inject(method = "test", at = @At("HEAD"), cancellable = true)
|
||||
public void test(@Nullable LivingEntity baseEntity, LivingEntity targetEntity, CallbackInfoReturnable<Boolean> ci) {
|
||||
public void test(ServerLevel serverLevel, LivingEntity baseEntity, LivingEntity targetEntity, CallbackInfoReturnable<Boolean> cir) {
|
||||
if (targetEntity instanceof ServerPlayer player) {
|
||||
if (player.level().getGameRules().getBoolean(CobblemonGameRules.MOB_TARGET_IN_BATTLE)) return;
|
||||
if (serverLevel.getGameRules().get(CobblemonGameRules.MOB_TARGET_IN_BATTLE)) return;
|
||||
boolean targetInBattle = Cobblemon.INSTANCE.getBattleRegistry().getBattleByParticipatingPlayer(player) != null;
|
||||
if (targetInBattle) ci.setReturnValue(false);
|
||||
if (targetInBattle) cir.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.CobblemonVillagerProfessions;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import kotlin.Pair;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.model.EntityModel;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
||||
import net.minecraft.client.renderer.entity.layers.RenderLayer;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.monster.ZombieVillager;
|
||||
import net.minecraft.world.entity.npc.Villager;
|
||||
import net.minecraft.world.entity.npc.VillagerProfession;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(RenderLayer.class)
|
||||
public abstract class VillagerProfessionLayerMixin {
|
||||
@Inject(method = "renderColoredCutoutModel", at = @At(value = "HEAD"), cancellable = true)
|
||||
private static <T extends LivingEntity> void cobblemon$renderVillagerProfessionLayer(EntityModel<T> entityModel, ResourceLocation resourceLocation, PoseStack poseStack, MultiBufferSource multiBufferSource, int i, T livingEntity, int j, CallbackInfo ci) {
|
||||
if (resourceLocation.getNamespace().equals(Cobblemon.MODID)) {
|
||||
VillagerProfession profession = null;
|
||||
boolean isZombie = false;
|
||||
|
||||
if (livingEntity instanceof Villager) profession = ((Villager) livingEntity).getVillagerData().getProfession();
|
||||
if (livingEntity instanceof ZombieVillager) {
|
||||
profession = ((ZombieVillager) livingEntity).getVillagerData().getProfession();
|
||||
isZombie = true;
|
||||
}
|
||||
|
||||
Pair<String, String[]> override = CobblemonVillagerProfessions.INSTANCE.getNameTagOverride(profession);
|
||||
if (profession != null && override != null) {
|
||||
String entityName = ChatFormatting.stripFormatting(livingEntity.getName().getString());
|
||||
boolean nameMatches = false;
|
||||
for (String name: override.getSecond())
|
||||
if (entityName.endsWith(name)) {
|
||||
nameMatches = true;
|
||||
break;
|
||||
}
|
||||
if (nameMatches && resourceLocation.equals(getProfessionResourceLocation(resourceLocation.getNamespace(), ResourceLocation.parse(profession.name()).getPath(), isZombie))) {
|
||||
ResourceLocation textureLocation = getProfessionResourceLocation(resourceLocation.getNamespace(), override.getFirst(), isZombie);
|
||||
VertexConsumer vertexConsumer = multiBufferSource.getBuffer(RenderType.entityCutoutNoCull(textureLocation));
|
||||
entityModel.renderToBuffer(poseStack, vertexConsumer, i, LivingEntityRenderer.getOverlayCoords(livingEntity, 0.0F), j);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ResourceLocation getProfessionResourceLocation(String namespace, String profession, Boolean isZombie) {
|
||||
return ResourceLocation.fromNamespaceAndPath(namespace, "textures/entity/" + (isZombie ? "zombie_villager" : "villager") + "/profession/" + profession + ".png");
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(BlockEntity.class)
|
||||
public interface BlockEntityAccessor {
|
||||
@Accessor("level") Level getLevel();
|
||||
@Accessor("worldPosition") BlockPos getWorldPosition();
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.world.entity.vehicle.Boat;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(Boat.class)
|
||||
public interface BoatEntityAccessor {
|
||||
|
||||
@Accessor("lastYd")
|
||||
void setFallVelocity(double fallVelocity);
|
||||
|
||||
@Accessor("status")
|
||||
Boat.Status getLocation();
|
||||
}
|
||||
@@ -17,4 +17,4 @@ import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
public interface ChunkMapAccessor {
|
||||
@Accessor("entityMap")
|
||||
Int2ObjectMap<?> getEntityMap();
|
||||
}
|
||||
}
|
||||
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.core.dispenser.DispenseItemBehavior;
|
||||
import net.minecraft.world.level.block.DispenserBlock;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(DispenserBlock.class)
|
||||
public interface DispenserBlockAccessor {
|
||||
@Accessor("DISPENSER_REGISTRY")
|
||||
static Map<Item, DispenseItemBehavior> getItemBehaviors() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.client.gui.components.AbstractSelectionList;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(AbstractSelectionList.class)
|
||||
public interface EntryListWidgetAccessor {
|
||||
@Accessor("renderHeader")
|
||||
boolean getRenderHeader();
|
||||
}
|
||||
+4
-2
@@ -8,13 +8,15 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.client.gui.components.StateSwitchingButton;
|
||||
import net.minecraft.client.gui.components.CycleButton;
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(RecipeBookComponent.class)
|
||||
public interface RecipeBookComponentAccessor {
|
||||
@Accessor("filterButton")
|
||||
StateSwitchingButton getFilterButton();
|
||||
CycleButton<Boolean> getFilterButton();
|
||||
}
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(ServerPlayer.class)
|
||||
public interface ServerPlayerAccessor {
|
||||
@Invoker("setShoulderEntityLeft")
|
||||
public void cobblemon$setShoulderEntityLeft(CompoundTag nbt);
|
||||
@Invoker("setShoulderEntityRight")
|
||||
public void cobblemon$setShoulderEntityRight(CompoundTag nbt);
|
||||
@Invoker("respawnEntityOnShoulder")
|
||||
public void cobblemon$respawnEntityOnShoulder(CompoundTag nbt);
|
||||
}
|
||||
+1
-4
@@ -19,7 +19,4 @@ import java.util.Set;
|
||||
public interface TrackedEntityAccessor {
|
||||
@Accessor("seenBy")
|
||||
Set<ServerPlayerConnection> getSeenBy();
|
||||
|
||||
@Accessor("serverEntity")
|
||||
ServerEntity getServerEntity();
|
||||
}
|
||||
}
|
||||
|
||||
+14
-9
@@ -15,9 +15,12 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.world.Containers;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.ItemStackTemplate;
|
||||
import net.minecraft.world.item.alchemy.PotionBrewing;
|
||||
import net.minecraft.world.item.crafting.RecipeHolder;
|
||||
import net.minecraft.world.item.crafting.RecipeManager;
|
||||
@@ -32,7 +35,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Mixin(BrewingStandBlockEntity.class)
|
||||
public class BrewingStandBlockEntityMixin {
|
||||
|
||||
@@ -47,17 +49,17 @@ public class BrewingStandBlockEntityMixin {
|
||||
ItemStack itemStack = slots.get(3);
|
||||
for(int i = 0; i < 3; ++i) {
|
||||
if (!slots.get(i).isEmpty()){
|
||||
slots.set(i, recipe.getResult().copy());
|
||||
slots.set(i, recipe.getResult().create());
|
||||
}
|
||||
}
|
||||
|
||||
itemStack.shrink(1);
|
||||
if (itemStack.getItem().hasCraftingRemainingItem()) {
|
||||
ItemStack itemStack2 = new ItemStack(itemStack.getItem().getCraftingRemainingItem());
|
||||
ItemStackTemplate itemStack2 = itemStack.getItem().getCraftingRemainder();
|
||||
if (itemStack2 != null) {
|
||||
if (itemStack.isEmpty()) {
|
||||
itemStack = itemStack2;
|
||||
itemStack = itemStack2.create();
|
||||
} else {
|
||||
Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), itemStack2);
|
||||
Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), itemStack2.create());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +91,10 @@ public class BrewingStandBlockEntityMixin {
|
||||
}
|
||||
|
||||
BrewingStandInput input = new BrewingStandInput(ingredient, bottles);
|
||||
RecipeManager recipeManager = level.getRecipeManager();
|
||||
if (level.getServer() == null) {
|
||||
return null;
|
||||
}
|
||||
RecipeManager recipeManager = level.getServer().getRecipeManager();
|
||||
|
||||
Optional<RecipeHolder<BrewingStandRecipe>> recipeHolder =
|
||||
recipeManager.getRecipeFor(CobblemonRecipeTypes.INSTANCE.getBREWING_STAND(), input, level);
|
||||
@@ -106,7 +111,7 @@ public class BrewingStandBlockEntityMixin {
|
||||
|
||||
if (level != null) {
|
||||
|
||||
var rm = level.getRecipeManager();
|
||||
var rm = level.recipeAccess();
|
||||
|
||||
//Input slot
|
||||
if (slot == 3) {
|
||||
@@ -127,4 +132,4 @@ public class BrewingStandBlockEntityMixin {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-1
@@ -9,11 +9,17 @@
|
||||
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;
|
||||
@@ -23,7 +29,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
public abstract class BrewingStandMenuMixin {
|
||||
@Inject(method = "<init>(ILnet/minecraft/world/entity/player/Inventory;Lnet/minecraft/world/Container;Lnet/minecraft/world/inventory/ContainerData;)V", at = @At("TAIL"))
|
||||
private void captureLevel(int containerId, Inventory playerInventory, Container brewingStandContainer, ContainerData brewingStandData, CallbackInfo ci) {
|
||||
var recipeManager = playerInventory.player.level().getRecipeManager();
|
||||
var recipeManager = playerInventory.player.level().recipeAccess();
|
||||
for (Slot slot : ((BrewingStandMenu) (Object) this).slots) {
|
||||
if (slot instanceof RecipeAwareSlot awareSlot) {
|
||||
awareSlot.setRecipeManager(recipeManager);
|
||||
|
||||
+3
-4
@@ -12,8 +12,7 @@ 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 net.minecraft.world.item.crafting.RecipeAccess;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
@@ -24,10 +23,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
public class IngredientSlotMixin implements RecipeAwareSlot {
|
||||
|
||||
@Unique
|
||||
private RecipeManager cobblemon$recipeManager;
|
||||
private RecipeAccess cobblemon$recipeManager;
|
||||
|
||||
@Override
|
||||
public void setRecipeManager(RecipeManager recipeManager) {
|
||||
public void setRecipeManager(RecipeAccess recipeManager) {
|
||||
this.cobblemon$recipeManager = recipeManager;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ 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.item.crafting.RecipeAccess;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
@@ -23,10 +23,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
public class PotionSlotMixin implements RecipeAwareSlot {
|
||||
|
||||
@Unique
|
||||
private RecipeManager cobblemon$recipeManager;
|
||||
private RecipeAccess cobblemon$recipeManager;
|
||||
|
||||
@Override
|
||||
public void setRecipeManager(RecipeManager recipeManager) {
|
||||
public void setRecipeManager(RecipeAccess recipeManager) {
|
||||
this.cobblemon$recipeManager = recipeManager;
|
||||
}
|
||||
|
||||
|
||||
+2
-3
@@ -21,7 +21,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
@Mixin(AbstractClientPlayer.class)
|
||||
public class AbstractClientPlayerMixin {
|
||||
@Inject(
|
||||
method = "getFieldOfViewModifier()F",
|
||||
method = "getFieldOfViewModifier",
|
||||
at = @At(
|
||||
value = "HEAD"
|
||||
),
|
||||
@@ -35,8 +35,7 @@ public class AbstractClientPlayerMixin {
|
||||
// Only modify fov through riding if the pokedex is not open
|
||||
AbstractClientPlayer player = (AbstractClientPlayer) (Object) this;
|
||||
// Only modify fov for the driver and not the passengers
|
||||
if (player != null && player.isPassenger() && player.getVehicle() instanceof PokemonEntity && player.getVehicle().getControllingPassenger() == player) {
|
||||
PokemonEntity ride = (PokemonEntity) player.getVehicle();
|
||||
if (player != null && player.isPassenger() && player.getVehicle() instanceof PokemonEntity ride && player.getVehicle().getControllingPassenger() == player) {
|
||||
|
||||
// Return custom fov mult for riding
|
||||
cir.setReturnValue(ride.rideFovMult());
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.client.render.player.MountedPlayerRenderer;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import net.minecraft.client.model.AgeableListModel;
|
||||
import net.minecraft.client.model.HumanoidModel;
|
||||
import net.minecraft.client.model.Model;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
/**
|
||||
* This mixin adds to the head of the renderToBuffer function and allows us to detect if it is a HumanoidModel and
|
||||
* is being rendered as part of a player in the world who is riding a PokemonEntity. If so we need to obey any
|
||||
* root animations that have been applied earlier.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since May 16, 2025
|
||||
*/
|
||||
@Mixin(AgeableListModel.class)
|
||||
public class AgeableListModelMixin {
|
||||
@Inject(method = "renderToBuffer", at = @At("HEAD"))
|
||||
private void cobblemon$renderToBuffer(
|
||||
PoseStack poseStack,
|
||||
VertexConsumer vertexConsumer,
|
||||
int packedLight,
|
||||
int packedOverlay,
|
||||
int colour,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
Model model = (Model) (Object) this;
|
||||
if (model instanceof HumanoidModel<?> && MountedPlayerRenderer.shouldApplyRootAnimation) {
|
||||
MountedPlayerRenderer.INSTANCE.animateRoot(poseStack);
|
||||
}
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.duck.AvatarRenderStateDuck;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.entity.state.AvatarRenderState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
|
||||
@Mixin(AvatarRenderState.class)
|
||||
public class AvatarRenderStateMixin implements AvatarRenderStateDuck {
|
||||
@Unique
|
||||
private @Nullable AbstractClientPlayer cobblemon$mountedPlayer;
|
||||
|
||||
@Unique
|
||||
private @Nullable PokemonEntity cobblemon$mountedPokemon;
|
||||
|
||||
@Override
|
||||
public @Nullable AbstractClientPlayer cobblemon$getMountedPlayer() {
|
||||
return this.cobblemon$mountedPlayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setMountedPlayer(@Nullable AbstractClientPlayer player) {
|
||||
this.cobblemon$mountedPlayer = player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable PokemonEntity cobblemon$getMountedPokemon() {
|
||||
return this.cobblemon$mountedPokemon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setMountedPokemon(@Nullable PokemonEntity pokemonEntity) {
|
||||
this.cobblemon$mountedPokemon = pokemonEntity;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.duck.AvatarRenderStateDuck;
|
||||
import com.cobblemon.mod.common.duck.LivingEntityRenderStateDuck;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.entity.player.AvatarRenderer;
|
||||
import net.minecraft.client.renderer.entity.state.AvatarRenderState;
|
||||
import net.minecraft.world.entity.Avatar;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(AvatarRenderer.class)
|
||||
public abstract class AvatarRendererMixin {
|
||||
@Inject(method = "extractRenderState", at = @At("TAIL"))
|
||||
private void cobblemon$captureMountedPlayer(Avatar avatar, AvatarRenderState state, float partialTick, CallbackInfo ci) {
|
||||
AvatarRenderStateDuck duck = (AvatarRenderStateDuck) state;
|
||||
LivingEntityRenderStateDuck livingDuck = (LivingEntityRenderStateDuck) state;
|
||||
if (avatar instanceof AbstractClientPlayer player && player.getVehicle() instanceof PokemonEntity pokemonEntity) {
|
||||
duck.cobblemon$setMountedPlayer(player);
|
||||
duck.cobblemon$setMountedPokemon(pokemonEntity);
|
||||
state.isCrouching = false;
|
||||
} else {
|
||||
duck.cobblemon$setMountedPlayer(null);
|
||||
duck.cobblemon$setMountedPokemon(null);
|
||||
}
|
||||
}
|
||||
|
||||
@ModifyExpressionValue(
|
||||
method = "getRenderOffset(Lnet/minecraft/client/renderer/entity/state/AvatarRenderState;)Lnet/minecraft/world/phys/Vec3;",
|
||||
at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/entity/state/HumanoidRenderState;isCrouching:Z", opcode = Opcodes.GETFIELD)
|
||||
)
|
||||
private boolean cobblemon$disableMountedCrouchOffset(boolean isCrouching, AvatarRenderState state) {
|
||||
AvatarRenderStateDuck duck = (AvatarRenderStateDuck) state;
|
||||
if (duck.cobblemon$getMountedPlayer() != null && duck.cobblemon$getMountedPokemon() != null) {
|
||||
return false;
|
||||
}
|
||||
return isCrouching;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,32 +12,36 @@ import com.cobblemon.mod.common.api.riding.Rideable;
|
||||
import com.cobblemon.mod.common.client.MountedPokemonAnimationRenderController;
|
||||
import com.cobblemon.mod.common.client.render.camera.MountedCameraRenderer;
|
||||
import com.cobblemon.mod.common.duck.CameraDuck;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.joml.Vector3f;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(Camera.class)
|
||||
public abstract class CameraMixin implements CameraDuck {
|
||||
@Shadow private float eyeHeight;
|
||||
@Shadow private float eyeHeightOld;
|
||||
@Shadow private BlockGetter level;
|
||||
@Shadow private Level level;
|
||||
@Shadow private Entity entity;
|
||||
@Final @Shadow private Vector3f forwards;
|
||||
@Final @Shadow private Vector3f up;
|
||||
@Final @Shadow private Vector3f left;
|
||||
@Shadow private float yRot;
|
||||
@Shadow private float xRot;
|
||||
|
||||
@Shadow protected abstract void setPosition(Vec3 pos);
|
||||
@Shadow private Vec3 position;
|
||||
@Shadow @Final private BlockPos.MutableBlockPos blockPosition;
|
||||
@Shadow private int matrixPropertiesDirty;
|
||||
|
||||
@Override public BlockGetter cobblemon$getLevel() {
|
||||
return level;
|
||||
@@ -59,15 +63,19 @@ public abstract class CameraMixin implements CameraDuck {
|
||||
@Override public float cobblemon$getYRot() { return yRot; }
|
||||
@Override public void cobblemon$setYRot(float yRot) { this.yRot = yRot; }
|
||||
|
||||
@WrapOperation(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;setPosition(DDD)V"))
|
||||
public void cobblemon$positionCamera(Camera instance, double x, double y, double z, Operation<Void> original, @Local(ordinal = 1, argsOnly = true) boolean thirdPersonReverse) {
|
||||
Entity entity = instance.getEntity();
|
||||
@Override public void cobblemon$markDirty() { this.matrixPropertiesDirty |= 3; }
|
||||
|
||||
@Inject(method = "setPosition(DDD)V", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$positionCamera(double x, double y, double z, CallbackInfo ci) {
|
||||
if (this.entity == null) return;
|
||||
Entity entity = this.entity;
|
||||
Entity vehicle = entity.getVehicle();
|
||||
boolean thirdPersonReverse = Minecraft.getInstance().options.getCameraType().isMirrored();
|
||||
MountedPokemonAnimationRenderController.INSTANCE.reset();
|
||||
|
||||
if(vehicle instanceof Rideable){
|
||||
Vec3 position = MountedCameraRenderer.INSTANCE.getCameraPosition(
|
||||
instance,
|
||||
if (vehicle instanceof Rideable) {
|
||||
Vec3 ridePos = MountedCameraRenderer.INSTANCE.getCameraPosition(
|
||||
(Camera) (Object) this,
|
||||
entity,
|
||||
vehicle,
|
||||
thirdPersonReverse,
|
||||
@@ -75,14 +83,17 @@ public abstract class CameraMixin implements CameraDuck {
|
||||
eyeHeightOld
|
||||
);
|
||||
|
||||
if(position != null) {
|
||||
setPosition(position);
|
||||
if (ridePos != null) {
|
||||
// Directly set the position field instead of calling setPosition(Vec3)
|
||||
this.position = ridePos;
|
||||
this.blockPosition.set(ridePos.x, ridePos.y, ridePos.z);
|
||||
|
||||
ci.cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// reset the rotation values if it is now not being ridden.
|
||||
MountedCameraRenderer.INSTANCE.setSmoothRotation(null);
|
||||
original.call(instance, x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.duck.ChannelDuck;
|
||||
import com.mojang.blaze3d.audio.Channel;
|
||||
import org.lwjgl.openal.AL10;
|
||||
import org.lwjgl.openal.AL11;
|
||||
import org.lwjgl.openal.EXTEfx;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
@Mixin(Channel.class)
|
||||
public abstract class ChannelMixin implements ChannelDuck {
|
||||
|
||||
@Shadow
|
||||
private int source;
|
||||
|
||||
// Ids of effects applied to the channel
|
||||
private int cobblemon$lowPassFilterId = 0;
|
||||
private int cobblemon$reverbEffectId = 0;
|
||||
private int cobblemon$reverbSlotId = 0;
|
||||
|
||||
@Override
|
||||
public void cobblemon$applyLowPassFilter(float gain, float hfGain) {
|
||||
// Delete old filter if it exists
|
||||
if (cobblemon$lowPassFilterId != 0) {
|
||||
AL10.alSourcei(source, EXTEfx.AL_DIRECT_FILTER, 0); // Detach filter from source
|
||||
EXTEfx.alDeleteFilters(cobblemon$lowPassFilterId); // Delete old filter
|
||||
cobblemon$lowPassFilterId = 0;
|
||||
}
|
||||
|
||||
// Generate a fresh filter
|
||||
int filterId = EXTEfx.alGenFilters();
|
||||
if (!EXTEfx.alIsFilter(filterId)) {
|
||||
System.err.println("Failed to create OpenAL low-pass filter");
|
||||
return;
|
||||
}
|
||||
|
||||
EXTEfx.alFilteri(filterId, EXTEfx.AL_FILTER_TYPE, EXTEfx.AL_FILTER_LOWPASS);
|
||||
EXTEfx.alFilterf(filterId, EXTEfx.AL_LOWPASS_GAIN, gain);
|
||||
EXTEfx.alFilterf(filterId, EXTEfx.AL_LOWPASS_GAINHF, hfGain);
|
||||
|
||||
AL10.alSourcei(source, EXTEfx.AL_DIRECT_FILTER, filterId);
|
||||
|
||||
// Save the new filter ID
|
||||
cobblemon$lowPassFilterId = filterId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$inverseAttenuation(float rolloffFactor) {
|
||||
AL10.alSourcei(source, AL10.AL_DISTANCE_MODEL, AL10.AL_INVERSE_DISTANCE);
|
||||
AL10.alSourcef(source, AL10.AL_ROLLOFF_FACTOR, rolloffFactor);
|
||||
AL10.alSourcef(source, AL10.AL_REFERENCE_DISTANCE, 1.0f);
|
||||
AL10.alSourcef(source, AL10.AL_MAX_DISTANCE, 0.0f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$clearFilters() {
|
||||
AL10.alSourcei(source, EXTEfx.AL_DIRECT_FILTER, 0);
|
||||
|
||||
if (EXTEfx.alIsFilter(cobblemon$lowPassFilterId)) {
|
||||
EXTEfx.alDeleteFilters(cobblemon$lowPassFilterId);
|
||||
cobblemon$lowPassFilterId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$applyReverb(float decayTime, float gain, float diffusion, float density) {
|
||||
// Clean up existing reverb first if it exists
|
||||
cobblemon$clearReverb();
|
||||
|
||||
// Create the effect object
|
||||
int effectId = EXTEfx.alGenEffects();
|
||||
if (!EXTEfx.alIsEffect(effectId)) {
|
||||
System.err.println("Failed to create OpenAL reverb effect");
|
||||
return;
|
||||
}
|
||||
|
||||
EXTEfx.alEffecti(effectId, EXTEfx.AL_EFFECT_TYPE, EXTEfx.AL_EFFECT_REVERB);
|
||||
EXTEfx.alEffectf(effectId, EXTEfx.AL_REVERB_DECAY_TIME, decayTime);
|
||||
EXTEfx.alEffectf(effectId, EXTEfx.AL_REVERB_GAIN, gain);
|
||||
EXTEfx.alEffectf(effectId, EXTEfx.AL_REVERB_DIFFUSION, diffusion);
|
||||
EXTEfx.alEffectf(effectId, EXTEfx.AL_REVERB_DENSITY, density);
|
||||
|
||||
// Create auxiliary effect slot and load effect into it
|
||||
int slotId = EXTEfx.alGenAuxiliaryEffectSlots();
|
||||
if (!EXTEfx.alIsAuxiliaryEffectSlot(slotId)) {
|
||||
System.err.println("Failed to create OpenAL auxiliary effect slot");
|
||||
EXTEfx.alDeleteEffects(effectId);
|
||||
return;
|
||||
}
|
||||
|
||||
EXTEfx.alAuxiliaryEffectSloti(slotId, EXTEfx.AL_EFFECTSLOT_EFFECT, effectId);
|
||||
|
||||
// Route source through the slot — send 0, no direct filter
|
||||
AL11.alSource3i(source, EXTEfx.AL_AUXILIARY_SEND_FILTER, slotId, 0, EXTEfx.AL_FILTER_NULL);
|
||||
|
||||
cobblemon$reverbEffectId = effectId;
|
||||
cobblemon$reverbSlotId = slotId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$clearReverb() {
|
||||
if (cobblemon$reverbSlotId != 0) {
|
||||
// Detach source from slot
|
||||
AL11.alSource3i(source, EXTEfx.AL_AUXILIARY_SEND_FILTER,
|
||||
EXTEfx.AL_EFFECTSLOT_NULL, 0, EXTEfx.AL_FILTER_NULL);
|
||||
EXTEfx.alDeleteAuxiliaryEffectSlots(cobblemon$reverbSlotId);
|
||||
cobblemon$reverbSlotId = 0;
|
||||
}
|
||||
if (cobblemon$reverbEffectId != 0) {
|
||||
EXTEfx.alDeleteEffects(cobblemon$reverbEffectId);
|
||||
cobblemon$reverbEffectId = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonRecipeCategories;
|
||||
import com.cobblemon.mod.common.item.crafting.CookingPotBookCategory;
|
||||
import com.cobblemon.mod.common.item.crafting.CookingPotRecipeBase;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import net.minecraft.client.ClientRecipeBook;
|
||||
import net.minecraft.client.RecipeBookCategories;
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeCollection;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.world.item.crafting.Recipe;
|
||||
import net.minecraft.world.item.crafting.RecipeHolder;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(ClientRecipeBook.class)
|
||||
public abstract class ClientRecipeBookMixin {
|
||||
|
||||
@Shadow
|
||||
protected static Map<RecipeBookCategories, List<List<RecipeHolder<?>>>> categorizeAndGroupRecipes(Iterable<RecipeHolder<?>> recipes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Shadow
|
||||
private Map<RecipeBookCategories, List<RecipeCollection>> collectionsByTab;
|
||||
|
||||
@Shadow
|
||||
private List<RecipeCollection> allCollections;
|
||||
|
||||
@Inject(method = "getCategory", at = @At(value = "HEAD"), cancellable = true)
|
||||
private static void addCustomCategory(RecipeHolder<?> recipe, CallbackInfoReturnable<RecipeBookCategories> cir) {
|
||||
Recipe<?> recipe2 = recipe.value();
|
||||
if (recipe2 instanceof CookingPotRecipeBase) {
|
||||
CookingPotBookCategory category = ((CookingPotRecipeBase) recipe2).getCategory();
|
||||
RecipeBookCategories var7;
|
||||
switch (category) {
|
||||
case MISC -> var7 = CobblemonRecipeCategories.COOKING_POT_MISC.toVanillaCategory();
|
||||
case FOODS -> var7 = CobblemonRecipeCategories.COOKING_POT_FOODS.toVanillaCategory();
|
||||
case MEDICINES -> var7 = CobblemonRecipeCategories.COOKING_POT_MEDICINES.toVanillaCategory();
|
||||
case COMPLEX_DISHES -> var7 = CobblemonRecipeCategories.COOKING_POT_COMPLEX_DISHES.toVanillaCategory();
|
||||
default -> throw new MatchException(null, null);
|
||||
}
|
||||
cir.setReturnValue(var7);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "setupCollections", at = @At("RETURN"))
|
||||
private void addCustomAggregateCategories(Iterable<RecipeHolder<?>> recipes, RegistryAccess registryAccess, CallbackInfo ci) {
|
||||
Map<RecipeBookCategories, List<List<RecipeHolder<?>>>> map = categorizeAndGroupRecipes(recipes);
|
||||
Map<RecipeBookCategories, List<RecipeCollection>> map2 = Maps.newHashMap();
|
||||
ImmutableList.Builder<RecipeCollection> builder = ImmutableList.builder();
|
||||
|
||||
map.forEach((recipeBookCategories, list) -> {
|
||||
List<RecipeCollection> collections = list.stream()
|
||||
.map(listx -> new RecipeCollection(registryAccess, listx))
|
||||
.peek(builder::add)
|
||||
.collect(ImmutableList.toImmutableList());
|
||||
map2.put(recipeBookCategories, collections);
|
||||
});
|
||||
RecipeBookCategories.AGGREGATE_CATEGORIES.forEach((recipeBookCategories, list) -> map2.put(recipeBookCategories, (List) list.stream().flatMap((recipeBookCategoriesx) -> ((List) map2.getOrDefault(recipeBookCategoriesx, ImmutableList.of())).stream()).collect(ImmutableList.toImmutableList())));
|
||||
CobblemonRecipeCategories.Companion.getCustomAggregateCategories().forEach((recipeBookCategories, list) -> map2.put(recipeBookCategories, (List) list.stream().flatMap((recipeBookCategoriesx) -> ((List) map2.getOrDefault(recipeBookCategoriesx, ImmutableList.of())).stream()).collect(ImmutableList.toImmutableList())));
|
||||
|
||||
this.collectionsByTab = ImmutableMap.copyOf(map2);
|
||||
this.allCollections = builder.build();
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.mojang.blaze3d.platform.cursor.CursorType;
|
||||
import net.minecraft.client.gui.GuiGraphicsExtractor;
|
||||
import net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen;
|
||||
import net.minecraft.world.item.CreativeModeTab;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
@Mixin(CreativeModeInventoryScreen.class)
|
||||
public abstract class CreativeModeInventoryScreenMixin {
|
||||
|
||||
@Redirect(
|
||||
method = "renderTabButton",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/gui/GuiGraphicsExtractor;requestCursor(Lcom/mojang/blaze3d/platform/cursor/CursorType;)V"
|
||||
)
|
||||
)
|
||||
private void cobblemon$skipCreativeTabCursor(GuiGraphicsExtractor guiGraphics, CursorType cursorType, GuiGraphicsExtractor context, int mouseX, int mouseY, CreativeModeTab tab) {
|
||||
// 1.21.1 had no special cursor on creative tab hover; keep the arrow cursor for tab icons.
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.client.gui.ScrollingWidget;
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import net.minecraft.client.gui.components.AbstractSelectionList;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
@Mixin(AbstractSelectionList.class)
|
||||
public abstract class EntryListWidgetMixin {
|
||||
|
||||
@SuppressWarnings("ConstantValue")
|
||||
@ModifyExpressionValue(method = "getEntryAtPosition", at = @At(value = "CONSTANT", args = {"intValue=4"}))
|
||||
public int cobblemon$adjustOnlyIfNecessary(int original) {
|
||||
if(ScrollingWidget.class.isInstance(this)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return original;
|
||||
}
|
||||
}
|
||||
@@ -49,14 +49,14 @@ public class GameRendererMixin {
|
||||
}
|
||||
|
||||
@ModifyArg(
|
||||
method = "pick(Lnet/minecraft/world/entity/Entity;DDF)Lnet/minecraft/world/phys/HitResult;",
|
||||
method = "pick",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/entity/projectile/ProjectileUtil;getEntityHitResult(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/AABB;Ljava/util/function/Predicate;D)Lnet/minecraft/world/phys/EntityHitResult;"
|
||||
target = "Lnet/minecraft/world/phys/EntityHitResult;getEntity()Lnet/minecraft/world/entity/Entity;"
|
||||
),
|
||||
index = 4
|
||||
)
|
||||
private Predicate<Entity> filterPokemonVehicle(Predicate<Entity> original, @Local(ordinal = 0, argsOnly = true) Entity entity) {
|
||||
private Predicate<Entity> filterPokemonVehicle(Predicate<Entity> original, @Local Entity entity) {
|
||||
return (entityX) -> !(entity.getVehicle() == entityX && entityX instanceof PokemonEntity) && original.test(entityX);
|
||||
}
|
||||
|
||||
|
||||
+71
-53
@@ -8,15 +8,17 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.client.render.player.MountedPlayerRenderer;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.duck.AvatarRenderStateDuck;
|
||||
import com.cobblemon.mod.common.duck.LivingEntityRenderStateDuck;
|
||||
import com.cobblemon.mod.common.entity.PoseType;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.client.model.HumanoidModel;
|
||||
import net.minecraft.client.model.geom.ModelPart;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.entity.state.AvatarRenderState;
|
||||
import net.minecraft.client.renderer.entity.state.HumanoidRenderState;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
@@ -41,59 +43,75 @@ public class HumanoidModelMixin {
|
||||
@Shadow @Final
|
||||
public ModelPart body;
|
||||
|
||||
@Inject(method = "setupAnim*", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/model/geom/ModelPart;copyFrom(Lnet/minecraft/client/model/geom/ModelPart;)V", shift = At.Shift.BEFORE))
|
||||
public void cobblemon$animateRiders(
|
||||
LivingEntity entity,
|
||||
float limbSwing,
|
||||
float limbSwingAmount,
|
||||
float ageInTicks,
|
||||
float netHeadYaw,
|
||||
float headPitch,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
@Inject(
|
||||
method = "setupAnim(Lnet/minecraft/client/renderer/entity/state/HumanoidRenderState;)V",
|
||||
at = @At("TAIL")
|
||||
)
|
||||
public void cobblemon$animateRiders(HumanoidRenderState renderState, CallbackInfo ci) {
|
||||
MountedPlayerRenderer.shouldApplyRootAnimation = false;
|
||||
|
||||
if (MountedPlayerRenderer.relevantPartsByName.size() <= 1) {
|
||||
MountedPlayerRenderer.relevantPartsByName.put("arm_left", leftArm);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("arm_right", rightArm);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("leg_left", leftLeg);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("leg_right", rightLeg);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("head", head);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("hat", hat);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("torso", body);
|
||||
if (!(renderState instanceof AvatarRenderState avatarRenderState)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Entity vehicle = entity.getVehicle();
|
||||
if (vehicle instanceof PokemonEntity pokemonEntity && entity instanceof OrientationControllable) {
|
||||
var shouldRotatePlayerHead = pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) ->
|
||||
behaviour.shouldRotateRiderHead(settings, state, pokemonEntity)
|
||||
);
|
||||
|
||||
// If the player is on a rollable ride then use the ride local rotations to rotate the head
|
||||
// This is to allow the player head to face the correct direction when "freelooking"
|
||||
// TODO: find a way for this to work on built jars without borking head rotations.
|
||||
// if (entity instanceof RidePassenger playerRotater &&
|
||||
// vehicle instanceof OrientationControllable controller &&
|
||||
// controller.getOrientationController().isActive()) {
|
||||
// this.head.xRot = playerRotater.cobblemon$getRideXRot();
|
||||
// headPitch = playerRotater.cobblemon$getRideXRot();
|
||||
// this.head.yRot = playerRotater.cobblemon$getRideYRot();
|
||||
// netHeadYaw = playerRotater.cobblemon$getRideYRot();
|
||||
// }
|
||||
|
||||
if (!shouldRotatePlayerHead) {
|
||||
netHeadYaw = 0f;
|
||||
headPitch = 0f;
|
||||
if (this.head != null) {
|
||||
this.head.yRot = 0f;
|
||||
this.head.xRot = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(entity instanceof AbstractClientPlayer player)) return;
|
||||
|
||||
MountedPlayerRenderer.shouldApplyRootAnimation = true;
|
||||
MountedPlayerRenderer.INSTANCE.animate((HumanoidModel<AbstractClientPlayer>)(Object)this, pokemonEntity, player, netHeadYaw, headPitch, ageInTicks, limbSwing, limbSwingAmount);
|
||||
AvatarRenderStateDuck duck = (AvatarRenderStateDuck) avatarRenderState;
|
||||
LivingEntityRenderStateDuck livingDuck = (LivingEntityRenderStateDuck) avatarRenderState;
|
||||
AbstractClientPlayer player = duck.cobblemon$getMountedPlayer();
|
||||
PokemonEntity pokemonEntity = duck.cobblemon$getMountedPokemon();
|
||||
if (player == null || pokemonEntity == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int seatIndex = livingDuck.cobblemon$getMountedSeatIndex();
|
||||
String seatLocator = livingDuck.cobblemon$getMountedSeatLocator();
|
||||
PoseType poseType = livingDuck.cobblemon$getMountedPoseType();
|
||||
|
||||
if (seatIndex < 0 || poseType == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
MountedPlayerRenderer.relevantPartsByName.put("arm_left", leftArm);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("arm_right", rightArm);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("leg_left", leftLeg);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("leg_right", rightLeg);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("head", head);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("hat", hat);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("torso", body);
|
||||
|
||||
Entity vehicle = player.getVehicle();
|
||||
if (!(vehicle instanceof PokemonEntity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var shouldRotatePlayerHead = pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) ->
|
||||
behaviour.shouldRotateRiderHead(settings, state, pokemonEntity)
|
||||
);
|
||||
|
||||
float netHeadYaw = avatarRenderState.yRot;
|
||||
float headPitch = avatarRenderState.xRot;
|
||||
|
||||
if (!shouldRotatePlayerHead) {
|
||||
netHeadYaw = 0f;
|
||||
headPitch = 0f;
|
||||
this.head.yRot = 0f;
|
||||
this.head.xRot = 0f;
|
||||
}
|
||||
|
||||
MountedPlayerRenderer.INSTANCE.animate(
|
||||
(HumanoidModel<?>)(Object)this,
|
||||
pokemonEntity,
|
||||
player,
|
||||
avatarRenderState,
|
||||
seatIndex,
|
||||
seatLocator,
|
||||
poseType,
|
||||
netHeadYaw,
|
||||
headPitch,
|
||||
avatarRenderState.ageInTicks,
|
||||
avatarRenderState.walkAnimationPos,
|
||||
avatarRenderState.walkAnimationSpeed
|
||||
);
|
||||
MountedPlayerRenderer.shouldApplyRootAnimation = true;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.item.PokeBallItem;
|
||||
import com.cobblemon.mod.common.item.PokedexItem;
|
||||
import net.minecraft.client.renderer.entity.ItemEntityRenderer;
|
||||
import net.minecraft.client.renderer.entity.state.ItemEntityRenderState;
|
||||
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ItemEntityRenderer.class)
|
||||
public class ItemEntityRendererMixin {
|
||||
@Shadow @Final private ItemModelResolver itemModelResolver;
|
||||
|
||||
@Inject(method = "extractRenderState", at = @At("TAIL"))
|
||||
private void cobblemon$overrideDroppedItemModel(ItemEntity entity, ItemEntityRenderState state, float partialTick, CallbackInfo ci) {
|
||||
Identifier modelId = cobblemon$getGroundModel(entity.getItem());
|
||||
if (modelId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack renderStack = entity.getItem().copy();
|
||||
renderStack.set(DataComponents.ITEM_MODEL, modelId);
|
||||
this.itemModelResolver.updateForNonLiving(state.item, renderStack, ItemDisplayContext.GROUND, entity);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static Identifier cobblemon$getGroundModel(ItemStack stack) {
|
||||
if (stack.getItem() instanceof PokeBallItem pokeBallItem) {
|
||||
return cobblemon$asStandaloneModel(pokeBallItem.getPokeBall().getModel3d());
|
||||
}
|
||||
|
||||
if (stack.getItem() instanceof PokedexItem pokedexItem) {
|
||||
return cobblemon$asStandaloneModel(pokedexItem.getType().getItemModelPath("off"));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static Identifier cobblemon$asStandaloneModel(Identifier modelId) {
|
||||
return modelId.withPath(path -> path.startsWith("item/") ? path.substring("item/".length()) : path);
|
||||
}
|
||||
}
|
||||
+63
-2
@@ -9,16 +9,27 @@
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.item.PokeBallItem;
|
||||
import com.cobblemon.mod.common.item.PokedexItem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.ItemInHandRenderer;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.joml.Quaternionf;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
@@ -26,8 +37,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ItemInHandRenderer.class)
|
||||
public class ItemInHandRendererMixin {
|
||||
@Shadow @Final private ItemModelResolver itemModelResolver;
|
||||
|
||||
@Inject(method = "renderArmWithItem", at = @At(value = "HEAD"), cancellable = true)
|
||||
private void cobblemon$renderArmWithItem(AbstractClientPlayer abstractClientPlayer, float f, float g, InteractionHand interactionHand, float h, ItemStack itemStack, float i, PoseStack poseStack, MultiBufferSource multiBufferSource, int j, CallbackInfo ci) {
|
||||
private void cobblemon$renderArmWithItem(AbstractClientPlayer abstractClientPlayer, float f, float g, InteractionHand interactionHand, float h, ItemStack itemStack, float i, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int j, CallbackInfo ci) {
|
||||
if (abstractClientPlayer.isUsingItem() && abstractClientPlayer.getUseItem().getItem() instanceof PokedexItem) {
|
||||
ci.cancel();
|
||||
}
|
||||
@@ -36,10 +49,58 @@ public class ItemInHandRendererMixin {
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "renderItem", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$renderItem(LivingEntity entity, ItemStack stack, ItemDisplayContext displayContext, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int light, CallbackInfo ci) {
|
||||
Identifier modelId = cobblemon$getHeldModel(stack, entity, displayContext);
|
||||
if (modelId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack renderStack = stack.copy();
|
||||
renderStack.set(DataComponents.ITEM_MODEL, modelId);
|
||||
|
||||
ItemStackRenderState renderState = new ItemStackRenderState();
|
||||
this.itemModelResolver.updateForTopItem(renderState, renderStack, displayContext, entity.level(), entity, entity.getId() + displayContext.ordinal());
|
||||
renderState.submit(poseStack, submitNodeCollector, light, OverlayTexture.NO_OVERLAY, 0);
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
@Redirect(method = "renderHandsWithItems", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;mulPose(Lorg/joml/Quaternionf;)V"))
|
||||
private void cobblemon$renderHandswithItems(PoseStack instance, Quaternionf quaternion) {
|
||||
if (!(Minecraft.getInstance().player != null && Minecraft.getInstance().player.getVehicle() instanceof OrientationControllable controllable && controllable.getOrientationController().isActive())) {
|
||||
instance.mulPose(quaternion);
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static Identifier cobblemon$getHeldModel(ItemStack stack, LivingEntity entity, ItemDisplayContext displayContext) {
|
||||
if (!cobblemon$isHandContext(displayContext)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (stack.getItem() instanceof PokeBallItem pokeBallItem) {
|
||||
return cobblemon$asStandaloneModel(pokeBallItem.getPokeBall().getModel3d());
|
||||
}
|
||||
|
||||
if (stack.getItem() instanceof PokedexItem pokedexItem) {
|
||||
boolean isScanModel = entity instanceof AbstractClientPlayer && entity.getUseItem() == stack && entity.isUsingItem();
|
||||
boolean canOpenScreen = (entity.getOffhandItem() == stack && !(entity.getMainHandItem().getItem() instanceof PokedexItem)) || entity.getMainHandItem() == stack;
|
||||
return cobblemon$asStandaloneModel(pokedexItem.getType().getItemModelPath(isScanModel ? "scanning" : (canOpenScreen ? null : "off")));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static boolean cobblemon$isHandContext(ItemDisplayContext displayContext) {
|
||||
return displayContext == ItemDisplayContext.FIRST_PERSON_LEFT_HAND
|
||||
|| displayContext == ItemDisplayContext.FIRST_PERSON_RIGHT_HAND
|
||||
|| displayContext == ItemDisplayContext.THIRD_PERSON_LEFT_HAND
|
||||
|| displayContext == ItemDisplayContext.THIRD_PERSON_RIGHT_HAND;
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static Identifier cobblemon$asStandaloneModel(Identifier modelId) {
|
||||
return modelId.withPath(path -> path.startsWith("item/") ? path.substring("item/".length()) : path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.CobblemonItemComponents;
|
||||
import com.cobblemon.mod.common.CobblemonItems;
|
||||
import com.cobblemon.mod.common.ModAPI;
|
||||
import com.cobblemon.mod.common.item.PokeBallItem;
|
||||
import com.cobblemon.mod.common.item.PokedexItem;
|
||||
import com.cobblemon.mod.common.item.WearableItem;
|
||||
import com.cobblemon.mod.common.item.components.TMMoveComponent;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.ItemModelShaper;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.entity.ItemRenderer;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
/*
|
||||
I think it would be nice to maybe use the existing mixin we have for custom item rendering [BuiltinModelItemRendererMixin]
|
||||
Obviously that would require changes. Potentially each item renderer defines what modes it overrides for?
|
||||
*/
|
||||
@Mixin(ItemRenderer.class)
|
||||
public abstract class ItemRendererMixin {
|
||||
// ignore the hint saying implmentation is never null, if something crashes then it is null and causes red herrings
|
||||
@Unique private final String MODEL_PATH = (Cobblemon.implementation != null && Cobblemon.implementation.getModAPI() == ModAPI.FABRIC) ? "fabric_resource" : "standalone";
|
||||
|
||||
@Shadow @Final private ItemModelShaper itemModelShaper;
|
||||
|
||||
@Shadow public abstract void render(ItemStack stack, ItemDisplayContext renderMode, boolean leftHanded, PoseStack matrices, MultiBufferSource vertexConsumers, int light, int overlay, BakedModel model);
|
||||
|
||||
@Inject(
|
||||
method = "render(Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemDisplayContext;ZLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;IILnet/minecraft/client/resources/model/BakedModel;)V",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$overrideItemModel(ItemStack stack, ItemDisplayContext renderMode, boolean leftHanded, PoseStack matrices, MultiBufferSource multiBufferSource, int light, int overlay, BakedModel model, CallbackInfo ci) {
|
||||
boolean shouldBe2d = renderMode == ItemDisplayContext.GUI || renderMode == ItemDisplayContext.FIXED || stack.getItem() == CobblemonItems.TECHNICAL_MACHINE;
|
||||
ResourceLocation resourceLocation = null;
|
||||
if (shouldBe2d) {
|
||||
if (stack.getItem() instanceof PokeBallItem pokeBallItem) resourceLocation = pokeBallItem.getPokeBall().getModel2d();
|
||||
else if (stack.getItem() instanceof PokedexItem pokedexItem) resourceLocation = pokedexItem.getType().getItemSpritePath();
|
||||
else if (stack.getItem() == CobblemonItems.TECHNICAL_MACHINE) {
|
||||
TMMoveComponent component = stack.get(CobblemonItemComponents.TM_MOVE);
|
||||
if (component != null) {
|
||||
resourceLocation = new ResourceLocation(Cobblemon.MODID, "tm/" + component.getMove().getElementalType().showdownId() + "_tm");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (renderMode != ItemDisplayContext.HEAD && stack.getItem() instanceof WearableItem wearableItem) resourceLocation = wearableItem.getModel2d();
|
||||
|
||||
if (resourceLocation != null) {
|
||||
BakedModel replacementModel = this.itemModelShaper.getModelManager().getModel(new ModelResourceLocation(resourceLocation, "inventory"));
|
||||
if (!cobblemon$isSameModel(model, replacementModel)) {
|
||||
ci.cancel();
|
||||
render(stack, renderMode, leftHanded, matrices, multiBufferSource, light, overlay, replacementModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "getModel", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$getItemModel(ItemStack stack, Level world, LivingEntity entity, int seed, CallbackInfoReturnable<BakedModel> cir) {
|
||||
ResourceLocation resourceLocation = null;
|
||||
if (stack.getItem() instanceof PokeBallItem pokeBallItem) resourceLocation = pokeBallItem.getPokeBall().getModel3d();
|
||||
else if (stack.getItem() instanceof PokedexItem pokedexItem) {
|
||||
boolean isScanModel = entity instanceof Player && entity.getUseItem() == stack && entity.isUsingItem();
|
||||
boolean canOpenScreen = entity != null && ((entity.getOffhandItem() == stack && !(entity.getMainHandItem().getItem() instanceof PokedexItem)) || entity.getMainHandItem() == stack);
|
||||
resourceLocation = pokedexItem.getType().getItemModelPath(isScanModel ? "scanning" : (canOpenScreen ? null : "off"));
|
||||
}
|
||||
else if (stack.getItem() instanceof WearableItem wearableItem) resourceLocation = wearableItem.getModel3d();
|
||||
|
||||
if (resourceLocation != null) {
|
||||
BakedModel model = this.itemModelShaper.getModelManager().getModel(new ModelResourceLocation(resourceLocation, MODEL_PATH));
|
||||
ClientLevel clientWorld = world instanceof ClientLevel ? (ClientLevel) world : null;
|
||||
BakedModel overriddenModel = model.getOverrides().resolve(model, stack, clientWorld, entity, seed);
|
||||
cir.setReturnValue(overriddenModel == null ? this.itemModelShaper.getModelManager().getMissingModel() : overriddenModel);
|
||||
}
|
||||
}
|
||||
|
||||
// this method aims to cover an issue with modernfixes and it's "dynamic resource" causing the usual .equals check to always fail, resulting in a StackOverflow
|
||||
// this falls back to comparing the model contents (e.g. location of the texture, width and height)
|
||||
@Unique
|
||||
private static boolean cobblemon$isSameModel(BakedModel original, BakedModel replacement) {
|
||||
return original.equals(replacement) ||
|
||||
(original.getParticleIcon().contents().name().equals(replacement.getParticleIcon().contents().name()) &&
|
||||
original.getParticleIcon().contents().width() == replacement.getParticleIcon().contents().width() &&
|
||||
original.getParticleIcon().contents().height() == replacement.getParticleIcon().contents().height());
|
||||
}
|
||||
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.duck.LivingEntityRenderStateDuck;
|
||||
import com.cobblemon.mod.common.entity.PoseType;
|
||||
import net.minecraft.client.renderer.entity.state.LivingEntityRenderState;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
|
||||
@Mixin(LivingEntityRenderState.class)
|
||||
public class LivingEntityRenderStateMixin implements LivingEntityRenderStateDuck {
|
||||
@Unique
|
||||
private @Nullable LivingEntity cobblemon$mountedEntity;
|
||||
|
||||
@Unique
|
||||
private float cobblemon$mountedPartialTick;
|
||||
|
||||
@Unique
|
||||
private int cobblemon$mountedSeatIndex = -1;
|
||||
|
||||
@Unique
|
||||
private @Nullable String cobblemon$mountedSeatLocator;
|
||||
|
||||
@Unique
|
||||
private @Nullable PoseType cobblemon$mountedPoseType;
|
||||
|
||||
@Override
|
||||
public @Nullable LivingEntity cobblemon$getMountedEntity() {
|
||||
return this.cobblemon$mountedEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setMountedEntity(@Nullable LivingEntity entity) {
|
||||
this.cobblemon$mountedEntity = entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float cobblemon$getMountedPartialTick() {
|
||||
return this.cobblemon$mountedPartialTick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setMountedPartialTick(float partialTick) {
|
||||
this.cobblemon$mountedPartialTick = partialTick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int cobblemon$getMountedSeatIndex() {
|
||||
return this.cobblemon$mountedSeatIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setMountedSeatIndex(int seatIndex) {
|
||||
this.cobblemon$mountedSeatIndex = seatIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String cobblemon$getMountedSeatLocator() {
|
||||
return this.cobblemon$mountedSeatLocator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setMountedSeatLocator(@Nullable String seatLocator) {
|
||||
this.cobblemon$mountedSeatLocator = seatLocator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable PoseType cobblemon$getMountedPoseType() {
|
||||
return this.cobblemon$mountedPoseType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setMountedPoseType(@Nullable PoseType poseType) {
|
||||
this.cobblemon$mountedPoseType = poseType;
|
||||
}
|
||||
}
|
||||
+101
-8
@@ -8,30 +8,123 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.client.render.ClientPlayerIcon;
|
||||
import com.cobblemon.mod.common.client.render.entity.MountedLivingEntityRenderer;
|
||||
import com.cobblemon.mod.common.duck.LivingEntityRenderStateDuck;
|
||||
import com.cobblemon.mod.common.entity.PoseType;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.item.WearableItem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.model.EntityModel;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
||||
import net.minecraft.client.renderer.entity.state.AvatarRenderState;
|
||||
import net.minecraft.client.renderer.entity.state.LivingEntityRenderState;
|
||||
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||
import net.minecraft.client.renderer.state.level.CameraRenderState;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(LivingEntityRenderer.class)
|
||||
public class LivingEntityRendererMixin<T extends LivingEntity, M extends EntityModel<T>> {
|
||||
public class LivingEntityRendererMixin {
|
||||
@Shadow @Final protected ItemModelResolver itemModelResolver;
|
||||
|
||||
@Inject(
|
||||
method = "extractRenderState",
|
||||
at = @At("TAIL")
|
||||
)
|
||||
private void cobblemon$captureMountedEntity(LivingEntity entity, LivingEntityRenderState state, float partialTick, CallbackInfo ci) {
|
||||
LivingEntityRenderStateDuck duck = (LivingEntityRenderStateDuck) state;
|
||||
if (entity.isPassenger() && entity.getVehicle() instanceof PokemonEntity) {
|
||||
PokemonEntity pokemonEntity = (PokemonEntity) entity.getVehicle();
|
||||
int seatIndex = pokemonEntity.getPassengers().indexOf(entity);
|
||||
String seatLocator = null;
|
||||
PoseType poseType = pokemonEntity.getCurrentPoseType();
|
||||
if (seatIndex >= 0 && seatIndex < pokemonEntity.getSeats().size()) {
|
||||
seatLocator = pokemonEntity.getSeats().get(seatIndex).getLocator();
|
||||
if (seatLocator == null) {
|
||||
seatLocator = "seat_" + (seatIndex + 1);
|
||||
}
|
||||
} else {
|
||||
seatIndex = -1;
|
||||
}
|
||||
|
||||
duck.cobblemon$setMountedEntity(entity);
|
||||
duck.cobblemon$setMountedPartialTick(partialTick);
|
||||
duck.cobblemon$setMountedSeatIndex(seatIndex);
|
||||
duck.cobblemon$setMountedSeatLocator(seatLocator);
|
||||
duck.cobblemon$setMountedPoseType(poseType);
|
||||
} else {
|
||||
duck.cobblemon$setMountedEntity(null);
|
||||
duck.cobblemon$setMountedPartialTick(0.0F);
|
||||
duck.cobblemon$setMountedSeatIndex(-1);
|
||||
duck.cobblemon$setMountedSeatLocator(null);
|
||||
duck.cobblemon$setMountedPoseType(null);
|
||||
}
|
||||
|
||||
ItemStack headItem = entity.getItemBySlot(EquipmentSlot.HEAD);
|
||||
if (headItem.getItem() instanceof WearableItem wearableItem) {
|
||||
ItemStack renderHeadItem = headItem.copy();
|
||||
renderHeadItem.set(DataComponents.ITEM_MODEL, wearableItem.getModel3d().withPath(path -> path.startsWith("item/") ? path.substring("item/".length()) : path));
|
||||
this.itemModelResolver.updateForLiving(state.headItem, renderHeadItem, ItemDisplayContext.HEAD, entity);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "setupRotations",
|
||||
at = @At("HEAD")
|
||||
)
|
||||
private void cobblemon$modifyRoll(LivingEntity entity, PoseStack poseStack, float bob, float yBodyRot, float partialTick, float scale, CallbackInfo ci) {
|
||||
if (entity.isPassenger()) {
|
||||
var vehicle = entity.getVehicle();
|
||||
if (vehicle instanceof PokemonEntity pokemonEntity) {
|
||||
MountedLivingEntityRenderer.INSTANCE.render(entity, pokemonEntity, poseStack, bob, yBodyRot, partialTick, scale);
|
||||
}
|
||||
private void cobblemon$modifyRoll(LivingEntityRenderState state, PoseStack poseStack, float bodyRot, float scale, CallbackInfo ci) {
|
||||
LivingEntityRenderStateDuck duck = (LivingEntityRenderStateDuck) state;
|
||||
LivingEntity entity = duck.cobblemon$getMountedEntity();
|
||||
if (entity == null || !(entity.getVehicle() instanceof PokemonEntity pokemonEntity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MountedLivingEntityRenderer.INSTANCE.render(
|
||||
entity,
|
||||
pokemonEntity,
|
||||
poseStack,
|
||||
state.walkAnimationPos,
|
||||
bodyRot,
|
||||
duck.cobblemon$getMountedPartialTick(),
|
||||
scale
|
||||
);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "submit",
|
||||
at = @At("TAIL")
|
||||
)
|
||||
private void cobblemon$renderPlayerIcon(
|
||||
LivingEntityRenderState state,
|
||||
PoseStack poseStack,
|
||||
SubmitNodeCollector submitNodeCollector,
|
||||
CameraRenderState cameraRenderState,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
if (!(state instanceof AvatarRenderState avatarState)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var level = Minecraft.getInstance().level;
|
||||
if (level == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var entity = level.getEntity(avatarState.id);
|
||||
if (entity instanceof Player player) {
|
||||
ClientPlayerIcon.Companion.onRenderPlayer(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,14 +23,13 @@ import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket;
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket;
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdatePassengerPositionPacket;
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateRiderRotationPacket;
|
||||
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.Input;
|
||||
import net.minecraft.client.player.ClientInput;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
@@ -65,7 +64,7 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
@Shadow
|
||||
private float jumpRidingScale;
|
||||
|
||||
@Shadow public Input input;
|
||||
@Shadow public ClientInput input;
|
||||
|
||||
@Shadow private int autoJumpTime;
|
||||
|
||||
@@ -89,6 +88,7 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
private void cobblemon$updateOrientationControllerRideTick(CallbackInfo ci) {
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
|
||||
var driver = (LocalPlayer)(Object)this;
|
||||
var vehicle = driver.getVehicle();
|
||||
if (!(this.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
|
||||
@@ -121,7 +121,6 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
Vector3f lastSentDriverInput = ((PlayerDuck)this).getLastSentDriverInput();
|
||||
if (driverInput.equals(lastSentDriverInput)) return;
|
||||
((PlayerDuck)this).setLastSentDriverInput(driverInput);
|
||||
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateDriverInputPacket(driverInput));
|
||||
}
|
||||
|
||||
@@ -143,28 +142,15 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
cobblemon$lastRideYRot != rideYRot ||
|
||||
cobblemon$lastRideEyePos != rideEyePos
|
||||
) {
|
||||
|
||||
// Update 'last' values
|
||||
cobblemon$lastRideXRot = rideXRot;
|
||||
cobblemon$lastRideYRot = rideYRot;
|
||||
cobblemon$lastRideEyePos = rideEyePos;
|
||||
|
||||
CobblemonNetwork.INSTANCE.sendToServer(
|
||||
new ServerboundUpdateRiderRotationPacket(rideXRot, rideYRot, rideEyePos)
|
||||
);
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateRiderRotationPacket(rideXRot, rideYRot, rideEyePos));
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("TAIL"))
|
||||
private void cobblemon$updatePassengerPosition(CallbackInfo ci) {
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
if (!(this.getVehicle() instanceof PokemonEntity pokemonEntity)) return;
|
||||
if (pokemonEntity.getSeatForPassenger(this) == null) return;
|
||||
|
||||
var offset = this.position().subtract(pokemonEntity.position());
|
||||
CobblemonNetwork.INSTANCE.sendToServer(
|
||||
new ServerboundUpdatePassengerPositionPacket(this.getId(), offset)
|
||||
);
|
||||
}
|
||||
|
||||
@Unique
|
||||
@@ -201,22 +187,26 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
|
||||
@Inject(method = "aiStep", at = @At("HEAD"))
|
||||
private void cobblemon$aiStep(CallbackInfo ci) {
|
||||
boolean jumpPressed = this.input.keyPresses.jump();
|
||||
this.cobblemon$isDoubleJumping = false;
|
||||
this.cobblemon$isJumping = this.input.jumping;
|
||||
this.cobblemon$isJumping = jumpPressed;
|
||||
}
|
||||
|
||||
@Inject(method = "aiStep", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;isSprinting()Z", shift = At.Shift.BEFORE))
|
||||
private void cobblemon$updateDoubleJumping(CallbackInfo ci) {
|
||||
if (!this.cobblemon$isJumping && this.input.jumping && this.autoJumpTime <= 0 && !this.isSwimming()) {
|
||||
if (!this.cobblemon$isJumping && this.input.keyPresses.jump() && this.autoJumpTime <= 0 && !this.isSwimming()) {
|
||||
PokemonEntity pokemonEntity = this.getVehicle() instanceof PokemonEntity vehiclePokemon ? vehiclePokemon : null;
|
||||
if (this.cobblemon$survivalJumpTriggerTime != 0) {
|
||||
this.cobblemon$isDoubleJumping = true;
|
||||
this.cobblemon$survivalJumpTriggerTime = 0;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.cobblemon$survivalJumpTriggerTime = 12;
|
||||
if (pokemonEntity != null) {
|
||||
this.cobblemon$isDoubleJumping = true;
|
||||
this.cobblemon$survivalJumpTriggerTime = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (this.cobblemon$survivalJumpTriggerTime > 0) {
|
||||
} else if (this.cobblemon$survivalJumpTriggerTime > 0) {
|
||||
this.cobblemon$survivalJumpTriggerTime--;
|
||||
}
|
||||
}
|
||||
@@ -230,10 +220,9 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
private void cobblemon$isHandsBusy(CallbackInfoReturnable<Boolean> cir) {
|
||||
Entity vehicle = this.getVehicle();
|
||||
if (vehicle instanceof PokemonEntity pokemonEntity) {
|
||||
Seat seat = pokemonEntity.getSeatForPassenger(this);;
|
||||
if (seat != null) {
|
||||
cir.setReturnValue(seat.getHandsBusy());
|
||||
}
|
||||
int seatIndex = pokemonEntity.getPassengers().indexOf(this);
|
||||
Seat seat = pokemonEntity.getSeats().get(seatIndex);
|
||||
cir.setReturnValue(seat.getHandsBusy());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.client.CobblemonBakingOverrides;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.color.block.BlockColors;
|
||||
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||
import net.minecraft.client.resources.model.BlockStateModelLoader;
|
||||
import net.minecraft.client.resources.model.ModelBakery;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.client.resources.model.UnbakedModel;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.packs.resources.Resource;
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(ModelBakery.class)
|
||||
public abstract class ModelLoaderMixin {
|
||||
@Shadow abstract UnbakedModel getModel(ResourceLocation resourceLocation);
|
||||
|
||||
@Shadow protected abstract void registerModel(ModelResourceLocation modelId, UnbakedModel unbakedModel);
|
||||
|
||||
@Shadow protected abstract void loadItemModelAndDependencies(ResourceLocation resourceLocation);
|
||||
|
||||
@Unique
|
||||
List<String> dynamicFolders = Arrays.asList("egg", "tm");
|
||||
|
||||
@Inject(
|
||||
method = "<init>",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/util/profiling/ProfilerFiller;popPush(Ljava/lang/String;)V",
|
||||
ordinal = 1
|
||||
)
|
||||
)
|
||||
public void loadCustomItemModels(BlockColors blockColors,
|
||||
ProfilerFiller profiler,
|
||||
Map<ResourceLocation, BlockModel> jsonUnbakedModels,
|
||||
Map<ResourceLocation, List<BlockStateModelLoader.LoadedJson>> blockStates,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
/*
|
||||
* The models/item/*.json's only get loaded if there's an item in the registry that actually asks for it. It
|
||||
* naively looks for things in the root with an item ID and calls upon it, and some of those JSONs reference
|
||||
* other model JSONs and so it cascades a little bit. Used for block models but more importantly here, sprites.
|
||||
*
|
||||
* The thing about the eggs (and TMs) is, we really want the eggs to be addon-compatible in a way that doesn't restrict
|
||||
* the species that can have eggs, so we can't pre-plan all of them. This mixin looks for the things inside the
|
||||
* egg subfolder (which won't get loaded automagically) and manually inserts them into the unbaked model list so
|
||||
* Minecraft loads them for us. We'll then dynamically call these models from the ItemRendererMixin; so it's
|
||||
* hacky at the init stage and hacky at the render stage. Pretty cool in the gameplay stage though.
|
||||
*
|
||||
* - Hiro
|
||||
*/
|
||||
|
||||
dynamicFolders.forEach(folder -> {
|
||||
Map<ResourceLocation, Resource> map = Minecraft.getInstance().getResourceManager().listResources("models/item/" + folder, (t) -> true);
|
||||
map.forEach((key, value) -> {
|
||||
ResourceLocation resourceLocation = new ResourceLocation(key.getNamespace(), key.getPath().replace("models/item/", "").replace(".json", ""));
|
||||
this.loadItemModelAndDependencies(resourceLocation);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "<init>",
|
||||
at = @At("TAIL")
|
||||
)
|
||||
public void init(BlockColors blockColors,
|
||||
ProfilerFiller profiler,
|
||||
Map<ResourceLocation, BlockModel> jsonUnbakedModels,
|
||||
Map<ResourceLocation, List<BlockStateModelLoader.LoadedJson>> blockStates,
|
||||
CallbackInfo ci) {
|
||||
CobblemonBakingOverrides.INSTANCE.getModels().forEach(bakingOverride -> {
|
||||
var unbakedModel = this.getModel(bakingOverride.getModelLocation());
|
||||
this.registerModel(bakingOverride.getModelIdentifier(), unbakedModel);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.client.render.player.MountedPlayerRenderer;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import net.minecraft.client.model.HumanoidModel;
|
||||
import net.minecraft.client.model.Model;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(Model.class)
|
||||
public abstract class ModelMixin {
|
||||
@Inject(
|
||||
method = "renderToBuffer(Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;III)V",
|
||||
at = @At("HEAD")
|
||||
)
|
||||
private void cobblemon$applyMountedRootAnimation(
|
||||
PoseStack poseStack,
|
||||
VertexConsumer vertexConsumer,
|
||||
int packedLight,
|
||||
int packedOverlay,
|
||||
int colour,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
if ((Object) this instanceof HumanoidModel<?> && MountedPlayerRenderer.shouldApplyRootAnimation) {
|
||||
MountedPlayerRenderer.INSTANCE.animateRoot(poseStack);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,12 +11,9 @@ package com.cobblemon.mod.common.mixin.client;
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.client.CobblemonClient;
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding;
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.RidingFreelookBinding;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext;
|
||||
import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import com.mojang.blaze3d.Blaze3D;
|
||||
@@ -27,7 +24,6 @@ import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.SmoothDouble;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
@@ -35,14 +31,12 @@ import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import com.cobblemon.mod.common.client.gui.party.PartyTutorialToasts;
|
||||
|
||||
import static com.google.common.primitives.Floats.min;
|
||||
import static net.minecraft.util.Mth.lerp;
|
||||
|
||||
@Mixin(MouseHandler.class)
|
||||
public abstract class MouseHandlerMixin {
|
||||
@Shadow private double accumulatedScrollY;
|
||||
@Shadow @Final private Minecraft minecraft;
|
||||
|
||||
@Unique SmoothDouble xMouseSmoother = new SmoothDouble();
|
||||
@@ -67,52 +61,6 @@ public abstract class MouseHandlerMixin {
|
||||
|
||||
@Unique private double cobblemon$timeDelta;
|
||||
|
||||
@Inject(
|
||||
method = "onScroll",
|
||||
at = @At(
|
||||
value = "FIELD",
|
||||
target="Lnet/minecraft/client/MouseHandler;accumulatedScrollY:D",
|
||||
opcode = Opcodes.PUTFIELD,
|
||||
ordinal = 2,
|
||||
shift = At.Shift.BEFORE
|
||||
),
|
||||
cancellable = true
|
||||
)
|
||||
public void cobblemon$scrollParty(long window, double horizontal, double vertical, CallbackInfo ci) {
|
||||
if (PartySendBinding.INSTANCE.getWasDown()) {
|
||||
int i = (int) accumulatedScrollY;
|
||||
if (i > 0) {
|
||||
accumulatedScrollY -= i;
|
||||
CobblemonClient.INSTANCE.getStorage().shiftSelected(false);
|
||||
ci.cancel();
|
||||
PartySendBinding.INSTANCE.actioned();
|
||||
PartyTutorialToasts.INSTANCE.onHoldKeyScrollSwitchedSlot();
|
||||
} else if (i < 0) {
|
||||
accumulatedScrollY -= i;
|
||||
CobblemonClient.INSTANCE.getStorage().shiftSelected(true);
|
||||
ci.cancel();
|
||||
PartySendBinding.INSTANCE.actioned();
|
||||
PartyTutorialToasts.INSTANCE.onHoldKeyScrollSwitchedSlot();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "onScroll",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/entity/player/Inventory;swapPaint(D)V"
|
||||
),
|
||||
cancellable = true
|
||||
)
|
||||
public void cobblemon$doPokedexZoom(long window, double horizontal, double vertical, CallbackInfo ci) {
|
||||
PokedexUsageContext usageContext = CobblemonClient.INSTANCE.getPokedexUsageContext();
|
||||
if (usageContext.getScanningGuiOpen()) {
|
||||
usageContext.adjustZoom(vertical);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@WrapWithCondition(
|
||||
method = "turnPlayer",
|
||||
at = @At(
|
||||
@@ -127,28 +75,10 @@ public abstract class MouseHandlerMixin {
|
||||
@Local(argsOnly = true) double d,
|
||||
@Local(argsOnly = true) double movementTime
|
||||
) {
|
||||
PokedexUsageContext usageContext = CobblemonClient.INSTANCE.getPokedexUsageContext();
|
||||
boolean returnValue = true;
|
||||
if (usageContext.getScanningGuiOpen()) {
|
||||
this.smoothTurnY.reset();
|
||||
this.smoothTurnX.reset();
|
||||
var defaultSensitivity = this.minecraft.options.sensitivity().get() * 0.6 + 0.2;
|
||||
var spyglassSensitivity = Math.pow(defaultSensitivity, 3);
|
||||
var lookSensitivity = spyglassSensitivity * 8.0;
|
||||
var sensitivity = lerp(usageContext.getFovMultiplier(), spyglassSensitivity, lookSensitivity);
|
||||
var yRotationFlip = this.minecraft.options.invertYMouse().get() ? -1 : 1;
|
||||
player.turn(this.accumulatedDX * sensitivity, (this.accumulatedDY * sensitivity * yRotationFlip));
|
||||
returnValue = false;
|
||||
}
|
||||
|
||||
var vehicle = player.getVehicle();
|
||||
if (!(vehicle instanceof PokemonEntity)) return returnValue;
|
||||
|
||||
// Clamp player rotation if riding and the vehicle demands it
|
||||
if (player.isPassenger() && vehicle instanceof PokemonEntity pokeVehicle) {
|
||||
pokeVehicle.clampPassengerRotation(player);
|
||||
}
|
||||
|
||||
// If the ride is not orientation controllable then return and perform the normal turnPlayer logic
|
||||
if (!(vehicle instanceof OrientationControllable controllableVehicle) || !controllableVehicle.getOrientationController().isActive()) {
|
||||
xMouseSmoother.reset();
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.client.render.ClientPlayerIcon;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.model.PlayerModel;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
||||
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(PlayerRenderer.class)
|
||||
public abstract class PlayerRendererMixin extends LivingEntityRenderer<AbstractClientPlayer, PlayerModel<AbstractClientPlayer>> {
|
||||
|
||||
public PlayerRendererMixin(EntityRendererProvider.Context context, PlayerModel<AbstractClientPlayer> model, float shadowRadius) {
|
||||
super(context, model, shadowRadius);
|
||||
}
|
||||
|
||||
@Inject(method = "render", at = @At(value = "TAIL"))
|
||||
public void renderPlayer(AbstractClientPlayer player, float f, float g, PoseStack poseStack, MultiBufferSource multiBufferSource, int i, CallbackInfo ci) {
|
||||
ClientPlayerIcon.Companion.onRenderPlayer(player);
|
||||
}
|
||||
|
||||
@WrapOperation(method = "getRenderOffset(Lnet/minecraft/client/player/AbstractClientPlayer;F)Lnet/minecraft/world/phys/Vec3;", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/AbstractClientPlayer;isCrouching()Z"))
|
||||
private boolean cobblemon$disableCrouchOffset(AbstractClientPlayer instance, Operation<Boolean> original) {
|
||||
if (instance.isPassenger() && instance.getVehicle() instanceof PokemonEntity) {
|
||||
return false;
|
||||
}
|
||||
return original.call(instance);
|
||||
}
|
||||
|
||||
@Inject(method = "setModelProperties", at = @At("TAIL"))
|
||||
private void cobblemon$setModelProperties(AbstractClientPlayer player, CallbackInfo ci) {
|
||||
if (player.isPassenger() && player.getVehicle() instanceof PokemonEntity) {
|
||||
PlayerModel<AbstractClientPlayer> playerModel = this.getModel();
|
||||
playerModel.crouching = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonRecipeCategories;
|
||||
import net.minecraft.client.ClientRecipeBook;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.RecipeBookCategories;
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent;
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeBookPage;
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeBookTabButton;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(RecipeBookComponent.class)
|
||||
public class RecipeBookComponentMixin {
|
||||
|
||||
@Shadow private ClientRecipeBook book;
|
||||
|
||||
@Shadow protected Minecraft minecraft;
|
||||
|
||||
@Shadow private int width;
|
||||
|
||||
@Shadow private int xOffset;
|
||||
|
||||
@Shadow private int height;
|
||||
|
||||
@Shadow @Final private RecipeBookPage recipeBookPage;
|
||||
|
||||
@Inject(method = "updateTabs", at = @At("HEAD"), cancellable = true)
|
||||
private void customUpdateTabs(CallbackInfo ci) {
|
||||
RecipeBookComponent instance = (RecipeBookComponent) (Object) this;
|
||||
int i = (width - 147) / 2 - xOffset - 30;
|
||||
int j = (height - 166) / 2 + 3;
|
||||
int k = 27;
|
||||
int l = 0;
|
||||
|
||||
for (RecipeBookTabButton recipeBookTabButton : instance.tabButtons) {
|
||||
RecipeBookCategories recipeBookCategories = recipeBookTabButton.getCategory();
|
||||
if (recipeBookCategories != RecipeBookCategories.CRAFTING_SEARCH && recipeBookCategories != RecipeBookCategories.FURNACE_SEARCH && recipeBookCategories != CobblemonRecipeCategories.COOKING_POT_SEARCH.toVanillaCategory()) {
|
||||
if (recipeBookTabButton.updateVisibility(book)) {
|
||||
recipeBookTabButton.setPosition(i, j + 27 * l++);
|
||||
recipeBookTabButton.startAnimation(minecraft);
|
||||
}
|
||||
} else {
|
||||
recipeBookTabButton.visible = true;
|
||||
recipeBookTabButton.setPosition(i, j + k * l++);
|
||||
}
|
||||
}
|
||||
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import net.minecraft.client.ClientRecipeBook;
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeBookTabButton;
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeCollection;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(RecipeBookTabButton.class)
|
||||
public class RecipeBookTabButtonMixin {
|
||||
|
||||
@Inject(method = "updateVisibility", at = @At("HEAD"), cancellable = true)
|
||||
private void customUpdateVisibility(ClientRecipeBook recipeBook, CallbackInfoReturnable<Boolean> cir) {
|
||||
RecipeBookTabButton instance = (RecipeBookTabButton) (Object) this;
|
||||
List<RecipeCollection> list = recipeBook.getCollection(instance.getCategory());
|
||||
boolean visible = false;
|
||||
if (list != null) {
|
||||
for (RecipeCollection recipeCollection : list) {
|
||||
if (recipeCollection.hasKnownRecipes() && recipeCollection.hasFitting()) {
|
||||
visible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
instance.visible = visible;
|
||||
cir.setReturnValue(visible);
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeCollection;
|
||||
import net.minecraft.stats.RecipeBook;
|
||||
import net.minecraft.world.entity.player.StackedContents;
|
||||
import net.minecraft.world.item.crafting.RecipeHolder;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Mixin(RecipeCollection.class)
|
||||
public class RecipeCollectionMixin {
|
||||
|
||||
@Shadow @Final private Set<RecipeHolder<?>> fitsDimensions;
|
||||
|
||||
@Shadow @Final private Set<RecipeHolder<?>> craftable;
|
||||
|
||||
@Shadow @Final private List<RecipeHolder<?>> recipes;
|
||||
|
||||
@Inject(method = "canCraft", at = @At("HEAD"), cancellable = true)
|
||||
private void customCanCraft(StackedContents handler, int width, int height, RecipeBook book, CallbackInfo ci) {
|
||||
for (RecipeHolder<?> recipeHolder : recipes) {
|
||||
boolean bl = recipeHolder.value().canCraftInDimensions(width, height) && book.contains(recipeHolder);
|
||||
if (bl) {
|
||||
fitsDimensions.add(recipeHolder);
|
||||
} else {
|
||||
fitsDimensions.remove(recipeHolder);
|
||||
}
|
||||
|
||||
if (bl && handler.canCraft(recipeHolder.value(), null)) {
|
||||
craftable.add(recipeHolder);
|
||||
} else {
|
||||
craftable.remove(recipeHolder);
|
||||
}
|
||||
}
|
||||
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -9,7 +9,6 @@
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.client.render.TextClipping;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.network.chat.Style;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
@@ -35,12 +34,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
* @author Hiroku
|
||||
* @since April 18th, 2025
|
||||
*/
|
||||
@Mixin(Font.StringRenderOutput.class)
|
||||
|
||||
@Mixin(targets = "net.minecraft.client.gui.Font$PreparedTextBuilder")
|
||||
public class StringRenderOutputMixin {
|
||||
@Inject(method = "accept", at = @At(value = "HEAD"), cancellable = true)
|
||||
public void onAccept(int i, Style style, int j, CallbackInfoReturnable<Boolean> cir) {
|
||||
if (!TextClipping.canDrawAnotherCharacter()) {
|
||||
cir.setReturnValue(true);
|
||||
cir.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client.accessor;
|
||||
|
||||
import com.mojang.blaze3d.systems.ScissorState;
|
||||
import net.minecraft.client.gui.GuiGraphicsExtractor;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(GuiGraphicsExtractor.class)
|
||||
public interface GuiGraphicsExtractorAccessor {
|
||||
@Accessor
|
||||
public GuiGraphicsExtractor.ScissorStack getScissorStack();
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client.accessor;
|
||||
|
||||
import net.minecraft.client.model.HumanoidModel;
|
||||
import net.minecraft.client.renderer.entity.state.HumanoidRenderState;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(HumanoidModel.class)
|
||||
public interface HumanoidModelAccessor {
|
||||
@Invoker("poseRightArm")
|
||||
void cobblemon$invokePoseRightArm(HumanoidRenderState renderState);
|
||||
|
||||
@Invoker("poseLeftArm")
|
||||
void cobblemon$invokePoseLeftArm(HumanoidRenderState renderState);
|
||||
|
||||
@Invoker("setupAttackAnimation")
|
||||
void cobblemon$invokeSetupAttackAnimation(HumanoidRenderState renderState);
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client.accessor;
|
||||
|
||||
import net.minecraft.client.model.EntityModel;
|
||||
import net.minecraft.client.renderer.entity.layers.RenderLayer;
|
||||
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
||||
import net.minecraft.client.renderer.entity.state.EntityRenderState;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(LivingEntityRenderer.class)
|
||||
public interface LivingEntityRendererAccessor<S extends EntityRenderState, M extends EntityModel<? super S>> {
|
||||
@Accessor("layers")
|
||||
List<RenderLayer<S, M>> cobblemon$getLayers();
|
||||
}
|
||||
+2
-2
@@ -19,7 +19,7 @@ import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
@@ -33,7 +33,7 @@ public final class SnapshotWarningMixin {
|
||||
private final Pattern VERSION = Pattern.compile("^(?<major>\\d+)\\.(?<minor>\\d+)\\.(?<patch>\\d+)$");
|
||||
|
||||
@Inject(method = "addInitialScreens", at = @At("TAIL"))
|
||||
public void cobblemon$addSnapshotWarningScreen(List<Function<Runnable, Screen>> output, CallbackInfo callback) {
|
||||
public void cobblemon$addSnapshotWarningScreen(List<Function<Runnable, Screen>> output, CallbackInfoReturnable<Boolean> callback) {
|
||||
if (CobblemonBuildDetails.SNAPSHOT && !this.cobblemon$isAcknowledged() && !SharedConstants.IS_RUNNING_IN_IDE) {
|
||||
output.add((runnable) -> new SnapshotWarningScreen((acknowledgement, dsa) -> {
|
||||
if (acknowledgement == SnapshotWarningScreen.Acknowledgement.NO) {
|
||||
|
||||
@@ -82,7 +82,7 @@ public abstract class EntityMixin {
|
||||
@Unique
|
||||
private void cobblemon$getCustomEyePos(CallbackInfoReturnable<Vec3> cir) {
|
||||
var entity = (Entity)(Object)this;
|
||||
if (entity.level().isClientSide) return;
|
||||
if (entity.level().isClientSide()) return;
|
||||
if (!(entity instanceof Player player)) return;
|
||||
if (!(player instanceof RidePassenger ridePassenger)) return;
|
||||
if (!(player.getVehicle() instanceof OrientationControllable vehicle)) return;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user