forked from mirrors/cobblemon
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43c0159471 |
+2
-3
@@ -12,8 +12,7 @@ out
|
||||
*.ipr
|
||||
*.iws
|
||||
*.iml
|
||||
.idea/*
|
||||
!.idea/icon.png
|
||||
.idea
|
||||
|
||||
# gradle
|
||||
build
|
||||
@@ -38,7 +37,7 @@ common/src/main/resources/assets/cobblemon/showdown
|
||||
/fabric/src/generated/resources/cobblemon-common.accesswidener
|
||||
/.ignored/
|
||||
common/.fabric
|
||||
.kotlin/
|
||||
|
||||
# MacOS
|
||||
.DS_Store
|
||||
.kotlin/sessions/kotlin-compiler-16609242564043830292.salive
|
||||
|
||||
+28
-147
@@ -3,155 +3,23 @@ image: amazoncorretto:21
|
||||
before_script:
|
||||
- export GRADLE_USER_HOME=`pwd`/.gradle
|
||||
|
||||
# TODO add client reference test process, search for import com.cobblemon.mod.common.client
|
||||
|
||||
stages:
|
||||
- preprocessing
|
||||
- packsquash
|
||||
- replaceresources
|
||||
- build
|
||||
- deploy
|
||||
|
||||
check_assets_cache:
|
||||
stage: preprocessing
|
||||
script:
|
||||
- echo "Checking if cached hash matches current hash"
|
||||
|
||||
# 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
|
||||
- echo "Current hash:"
|
||||
- cat current_hash.txt
|
||||
|
||||
# Check for the existence of the previous hash
|
||||
- if [[ -f assets_data_hash.txt ]]; then
|
||||
echo "Previous cached hash found:";
|
||||
cat assets_data_hash.txt;
|
||||
if cmp -s assets_data_hash.txt current_hash.txt; then
|
||||
echo "Hashes match, skipping PackSquash";
|
||||
rm -f run_packsquash.flag || true;
|
||||
else
|
||||
echo "Hashes differ, PackSquash needed";
|
||||
touch run_packsquash.flag;
|
||||
fi;
|
||||
else
|
||||
echo "No cached hash found, marking PackSquash as required";
|
||||
touch run_packsquash.flag;
|
||||
fi
|
||||
|
||||
# Save the current hash for future runs
|
||||
- echo "Saving current hash to cache";
|
||||
- cp current_hash.txt assets_data_hash.txt
|
||||
artifacts:
|
||||
paths:
|
||||
- current_hash.txt
|
||||
- assets_data_hash.txt
|
||||
- run_packsquash.flag
|
||||
expire_in: 7 days
|
||||
cache:
|
||||
key: "cache-${CI_COMMIT_REF_NAME}"
|
||||
paths:
|
||||
- assets_data_hash.txt
|
||||
- ./compressed_pack.zip
|
||||
|
||||
setup_resource_pack:
|
||||
stage: preprocessing
|
||||
script:
|
||||
- echo "Setting up fake resource pack"
|
||||
- mkdir ./fake_resource_pack
|
||||
- cp -r common/src/main/resources/assets common/src/main/resources/data ./fake_resource_pack/
|
||||
- echo '{"pack":{"pack_format":34,"description":"Fake Cobblemon Pack"}}' > ./fake_resource_pack/pack.mcmeta
|
||||
artifacts:
|
||||
paths:
|
||||
- ./fake_resource_pack/
|
||||
expire_in: 7 days
|
||||
|
||||
setup_packsquash:
|
||||
stage: preprocessing
|
||||
script:
|
||||
- echo "Installing wget & unzip"
|
||||
- yum install -y wget unzip
|
||||
- echo "Downloading PackSquash"
|
||||
- wget https://github.com/ComunidadAylas/PackSquash/releases/download/v0.4.0/PackSquash.CLI.executable.x86_64-unknown-linux-musl.zip
|
||||
- unzip PackSquash.CLI.executable.x86_64-unknown-linux-musl.zip -d ./packsquash_bin
|
||||
- echo "Creating PackSquash options.toml"
|
||||
- |
|
||||
cat <<EOF > ./options.toml
|
||||
pack_directory = "./fake_resource_pack/"
|
||||
output_file_path = "./compressed_pack.zip"
|
||||
zip_spec_conformance_level = "high"
|
||||
['**/*?.ogg']
|
||||
transcode_ogg = false
|
||||
two_pass_vorbis_optimization_and_validation = false
|
||||
sampling_frequency = 999999
|
||||
empty_audio_optimization=false
|
||||
EOF
|
||||
artifacts:
|
||||
paths:
|
||||
- ./packsquash_bin/
|
||||
- ./options.toml
|
||||
expire_in: 7 days
|
||||
|
||||
default:
|
||||
artifacts:
|
||||
expire_in: 7 days
|
||||
|
||||
run_packsquash:
|
||||
stage: packsquash
|
||||
dependencies:
|
||||
- check_assets_cache
|
||||
- setup_resource_pack
|
||||
- setup_packsquash
|
||||
script:
|
||||
- ls -l
|
||||
- if [[ ! -f ./compressed_pack.zip || -f run_packsquash.flag ]]; then
|
||||
echo "Running PackSquash";
|
||||
chmod +x ./packsquash_bin/packsquash;
|
||||
./packsquash_bin/packsquash ./options.toml;
|
||||
else
|
||||
echo "Skipping PackSquash; no changes detected and compressed pack exists";
|
||||
fi
|
||||
cache:
|
||||
key: "cache-${CI_COMMIT_REF_NAME}"
|
||||
policy: pull-push
|
||||
paths:
|
||||
- assets_data_hash.txt
|
||||
- ./compressed_pack.zip
|
||||
artifacts:
|
||||
paths:
|
||||
- ./compressed_pack.zip
|
||||
|
||||
replace_resources:
|
||||
stage: replaceresources
|
||||
dependencies:
|
||||
- run_packsquash
|
||||
script:
|
||||
- echo "Installing unzip"
|
||||
- yum install -y unzip
|
||||
|
||||
- echo "Unzipping compressed pack"
|
||||
- mkdir temp_unpack
|
||||
- unzip ./compressed_pack.zip -d temp_unpack
|
||||
|
||||
- echo "Removing original assets and data"
|
||||
- rm -rf common/src/main/resources/assets
|
||||
- rm -rf common/src/main/resources/data
|
||||
|
||||
- echo "Replacing assets and data"
|
||||
- mv temp_unpack/assets common/src/main/resources/
|
||||
- mv temp_unpack/data common/src/main/resources/
|
||||
artifacts:
|
||||
paths:
|
||||
- common/src/main/resources/
|
||||
#TODO add client reference test process, search for import com.cobblemon.mod.common.client
|
||||
|
||||
build:
|
||||
stage: build
|
||||
dependencies:
|
||||
- replace_resources
|
||||
only:
|
||||
- branches@cable-mc/cobblemon
|
||||
script:
|
||||
- export GRADLE_OPTS="-Xmx4G -Xms4G"
|
||||
- chmod +x ./gradlew
|
||||
- ./gradlew build
|
||||
artifacts:
|
||||
cache:
|
||||
key: "$CI_COMMIT_REF_NAME"
|
||||
policy: push
|
||||
paths:
|
||||
- neoforge/build/libs
|
||||
- fabric/build/libs
|
||||
@@ -160,26 +28,39 @@ publish:
|
||||
stage: deploy
|
||||
dependencies:
|
||||
- build
|
||||
cache:
|
||||
key: "CI_COMMIT_REF_NAME"
|
||||
policy: pull
|
||||
paths:
|
||||
- neoforge/build/libs/*.jar
|
||||
- fabric/build/libs/*.jar
|
||||
rules:
|
||||
- if: '$CI_PROJECT_PATH == "cable-mc/cobblemon" && $CI_COMMIT_BRANCH == "main"'
|
||||
- if: '$CI_COMMIT_BRANCH == "main"'
|
||||
script:
|
||||
- export GRADLE_OPTS="-Xmx4G -Xms4G"
|
||||
- chmod +x ./gradlew
|
||||
- ./gradlew publish
|
||||
artifacts:
|
||||
paths:
|
||||
- neoforge/build/libs/*.jar
|
||||
- fabric/build/libs/*.jar
|
||||
|
||||
deploy_artifacts:
|
||||
# Separate step to deploy the artifacts, save Norry the headache of keeping even more shit around
|
||||
deploy:
|
||||
stage: deploy
|
||||
dependencies:
|
||||
- build
|
||||
script:
|
||||
when: manual
|
||||
cache:
|
||||
key: "$CI_COMMIT_REF_NAME"
|
||||
policy: pull
|
||||
paths:
|
||||
- neoforge/build/libs/*.jar
|
||||
- fabric/build/libs/*.jar
|
||||
script:
|
||||
- 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 {} ./
|
||||
- mv neoforge/build/libs/*+*.jar ./
|
||||
- mv fabric/build/libs/*+*.jar ./
|
||||
- for f in *.jar; do mv "$f" "$(echo "$f" | sed s/+/b$CI_PIPELINE_IID+/)"; done
|
||||
artifacts:
|
||||
expire_in: 28 days
|
||||
paths:
|
||||
- ./*.jar
|
||||
# - neoforge/build/libs/*+*.jar
|
||||
# - fabric/build/libs/*+*.jar
|
||||
|
||||
Generated
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1 @@
|
||||
LambDynamicLights compat needs to be restored
|
||||
@@ -1,26 +0,0 @@
|
||||
### Additions
|
||||
- Rebuilt Pokémon AI to use Minecraft's Brain system, allowing for more complex behaviours and interactions.
|
||||
- As an early pass of this, pastured Pokémon will now sleep when appropriate, and may come up to you when they see you.
|
||||
- Probably also added a whole bunch of bugs.
|
||||
- Dog Pokémon (Growlithe, Arcanine, etc.) intimidate Skeletons.
|
||||
- Cat Pokémon (Meowth, Persian, etc.) intimidate Creepers and Phantoms.
|
||||
- Sleep-related Pokémon (Munsharna, Komala, etc.) intimidate Phantoms.
|
||||
- Some Pokémon naturally hunt each other.
|
||||
- Some Pokémon herd together.
|
||||
- Added a Behaviour Editor to the NPC editing screen.
|
||||
- Added /behaviouredit command for opening the Behaviour Editor on Pokémon and NPCs.
|
||||
- Editing variables for Pokémon is not yet supported.
|
||||
|
||||
### Developer
|
||||
- baseScale in NPCs has been removed from classes and presets, and in the entity it is replaced with hitboxScale and renderScale.
|
||||
- Added `EntityCallbacks` to `NPCEntity` and `PokemonEntity`. You can trigger custom callback types by using `[Entity].callbacks.process(...)`
|
||||
|
||||
### Fixes
|
||||
- Fixed Pokémon with a moving walk target frequently spinning in place as they re-calculate their path.
|
||||
|
||||
### MoLang & Datapacks
|
||||
- Added a `behaviours` datapack folder which motivates the Behaviour Editor screen on NPCs and Pokémon.
|
||||
- Added "callback" support on PokemonEntity and NPCEntity that allows MoLang scripts to be executed in response to certain scenarios.
|
||||
- Added very many behaviours to choose from.
|
||||
- Removed many NPC presets that now exist as behaviours. This is a breaking change if you are using NPCs with these presets.
|
||||
- NPCs with these presets should be modified to instead list under `"behaviours"` all the equivalent behaviours.
|
||||
@@ -1,35 +0,0 @@
|
||||
### Additions
|
||||
- Added the Campfire Pot, made from apricorns and placed onto campfires.
|
||||
- This pot can be used to make bait for fishing, Poké Cakes, Lure Cakes, local specialties, and potions (less efficiently than a brewing stand).
|
||||
- There is a different pot for each apricorn colour because at this point I think we may have an addiction.
|
||||
- Added Aprijuice, made from the Campfire Pot using apricorns with seasoning to give flavours.
|
||||
- Aprijuice can be fed to ride-able Pokémon to improve their riding characteristics, depending on the flavour and the Pokémon's nature.
|
||||
- Added Lure Cakes, made from the Campfire Pot using honey and berries.
|
||||
- Lure Cakes can be used to modify the spawn rate of Pokémon in the wild.
|
||||
- Added the Saccharine Tree, which can be found in the wild and is used to obtain Honey Bottles.
|
||||
- The leaves of the tree can be harvested to obtain honey, which can be used in the Campfire Pot to make Lure Cakes.
|
||||
- The Log of the tree can be interacted with using a honey bottle to create a Honey-Slathered Saccharine Log, which increases the change of spawning a Pokémon with a Hidden Ability.
|
||||
- Added Hearty Grains
|
||||
- Clicking on the Progress Arrow will show the JEI Recipe Book for the Campfire Pot, which will show all recipes that can be made with it.
|
||||
- Added a Ton of Redstone Compatibility.
|
||||
- Dispenser can now Honey and Unhoney:
|
||||
- Saccharine Log
|
||||
- Saccharine Leaves
|
||||
- Redstone can Close and Open the Lid of a Cooking Pot
|
||||
- Powered = Closed
|
||||
- Unpowered = Open
|
||||
- Hoppers can be used to insert items into a Cooking pot
|
||||
- Top = Seasonals
|
||||
- All Sides = Crafting
|
||||
- Bottom = Extract the Result
|
||||
- Observer will recognise when a Cooking pot is Closed or Opened
|
||||
- Comparator Calculates a Signal Strength depending on the items inside the cooking pot
|
||||
- Sculk Sensor
|
||||
- Saccharine Leaves
|
||||
- Opening and Closing the Cooking Pot
|
||||
- Saccharine Log
|
||||
|
||||
### Datapack and Addon Changes
|
||||
- Renamed the fishing_baits datapack folder to spawn_bait_effects.
|
||||
- Added `seasonings` datapack folder for controlling usable items in the campfire pot and what colour and flavour they apply.
|
||||
- Added campfire pot recipe type, which you could use to make anything work as fishing bait.
|
||||
@@ -0,0 +1,3 @@
|
||||
### Additions
|
||||
- Added the Poké Dex as a craftable item.
|
||||
- Poké Dexes can be placed on lecterns.
|
||||
@@ -1,13 +0,0 @@
|
||||
### Additions
|
||||
- Added functionality for marks.
|
||||
- Added data for all marks and ribbons from the mainline Pokémon games.
|
||||
- Implemented fishing, personality, weather, and time related marks, that can rarely be granted to a wild-spawned Pokémon.
|
||||
- Added marks screen within the summary UI.
|
||||
- Added `/givemark <player> <partySlot> <mark>` command to give a mark to a Pokémon.
|
||||
- Added `/takemark <player> <partySlot> <mark>` command to remove a mark from a Pokémon.
|
||||
- Added `/giveallmarks <player> <partySlot>` command to give all available marks to a Pokémon.
|
||||
|
||||
### MoLang & Datapacks
|
||||
- Added Flows for `bobber_spawn_pokemon_post`, `pokemon_entity_spawn`, and `fossil_revived`.
|
||||
- Added `marks` datapack folder.
|
||||
- Added MoLang functions `entity.is_in_rain`, `pokemon.add_marks(Mark...)`, `pokemon.add_potential_marks(Mark...)`, `pokemon.add_marks_with_chance(Mark...)`, `pokemon.apply_potential_marks`, and `world.is_snowing_at(x, y, z)`.
|
||||
@@ -0,0 +1,6 @@
|
||||
### Additions
|
||||
- Added `moves` option to PokemonProperties, allowing you to set the moves of a Pokémon in commands and spawn files.
|
||||
- Added /spawnnpc and /spawnnpcat commands.
|
||||
|
||||
### Fixes
|
||||
- Fixed sync issues with recently learned moves where their PP would not go down until you logout and in.
|
||||
@@ -0,0 +1,24 @@
|
||||
### Additions
|
||||
- Pokémon are now animated when seen in any GUI that isn't the party GUI.
|
||||
- Quirk animations can now occur for Pokémon that are shoulder mounted.
|
||||
|
||||
### Changes
|
||||
- Improved the performance of display cases that contain Pokémon photos.
|
||||
|
||||
### Fixes
|
||||
- Fixed some Pokémon photos in display cases flashing if the Pokémon has gender differences.
|
||||
- Fixed Bidoof and Jigglypuff sleep animations stopping after some time, causing them to be 'asleep' while T-posing menacingly.
|
||||
- Fixed entities not changing poses unless you're looking at them.
|
||||
- Fixed cries not playing on send-out if the Pokémon is off-screen.
|
||||
|
||||
### Developer
|
||||
- Rebuilt large swaths of the model animation code to simplify it.
|
||||
- Renamed a bunch of things from %Poseable% to %Posable% because spelling.
|
||||
- Renamed StatelessAnimation to PoseAnimation.
|
||||
- Renamed StatefulAnimation to ActiveAnimation.
|
||||
- Documented the animation system.
|
||||
|
||||
### Data Pack & Resource Pack Creators
|
||||
- Added MoLang compatibility in the isVisible property for transformed parts.
|
||||
- Added q.has_aspect('some_aspect') function to animations, posers, and entity particle effects.
|
||||
- Added support for conditional pose animations.
|
||||
@@ -1,38 +0,0 @@
|
||||
### Additions
|
||||
- Added ability to rename PC Boxes by clicking on the name of a box.
|
||||
- Added box options buttons for boxes, toggleable by clicking the right icon button in the bottom bar.
|
||||
- The option buttons on the left side allow for sorting the box by name, level, Pokédex number, gender, and type. Shift clicking allows for sorting in reverse order.
|
||||
- The button on the right allows for changing the box wallpaper.
|
||||
- 10 additional color-based wallpapers have been added.
|
||||
- 5 unlockable biome-based wallpapers have been added, which can be unlocked by visiting:
|
||||
- Forest biome
|
||||
- Ocean biome
|
||||
- Cave Biome
|
||||
- The End
|
||||
- The Nether
|
||||
- Added filter functionality in PC UI, which supports `PokemonProperties` (e.g. `shiny=yes` shows all shiny Pokémon).
|
||||
- Names can be filtered by exact or partial matches, e.g. entering "cha" will show Charmander, Charmeleon, etc.
|
||||
- Added `/changewallpaper <player> <boxNumber> <wallpaper>` command to change a box wallpaper through commands.
|
||||
- Added `/renamebox <player> <boxNumber> <name>` command to rename a PC box through commands.
|
||||
- Added IVs and EVs stat displays in PC.
|
||||
- The displays can be cycled through by scrolling when the display is hovered over.
|
||||
- Added ability to cycle through boxes by scrolling when the box is hovered over.
|
||||
- PC will now open to last box viewed within a session.
|
||||
|
||||
### Changes
|
||||
- Slots in pastures will now have darker backgrounds and italicised Pokémon names if the Pokémon is not owned by the player.
|
||||
- The pasture slot will show the name of the Pokémon owner when hovered if the Pokémon is not owned.
|
||||
- Increased the default PC box count from 30 to 40 to accommodate the fact that we have way more Pokémon now. If you've changed this config option then you'll need to edit it again after starting up with 1.7!
|
||||
|
||||
### Developer
|
||||
- Added `RenamePCBoxEvent.Pre` and `RenamePCBoxEvent.Post` events to prevent players from renaming a box or changing their input.
|
||||
- Added `ChangePCBoxWallpaperEvent.Pre` and `ChangePCBoxWallpaperEvent.Post` to prevent players from changing wallpapers or changing their selection.
|
||||
- Added `WallpaperCollectionEvent` which gets called when clients connect to a server, allowing the server to handle which of the client-found wallpapers it's allowed to move (collected wallpapers can be removed for example to make it "vanish" client-side).
|
||||
- Added `WallpaperUnlockedEvent`.
|
||||
- Renamed `SetPCBoxPokemonPacket` and the respective handler to `SetPCBoxPacket`.
|
||||
|
||||
### Addons
|
||||
- Added Flows for `player_tick_pre`, `player_tick_post`, `advancement_earned`, `right_clicked_entity`, `right_clicked_block`, `player_died`, `wallpaper_unlocked`.
|
||||
- Flows now have `q.` for any context properties in addition to the `c.` properties, making it a bit more convenient when calling other scripts from Flows.
|
||||
- Added `unlockable_pc_box_wallpapers` datapack folder for wallpapers that need to be unlocked before they're usable.
|
||||
- Wallpapers are loaded from `assets/<namespace>/textures/gui/pc/wallpaper/` and all wallpapers in this folder are available to the client to choose by default.
|
||||
@@ -1,4 +0,0 @@
|
||||
### Additions
|
||||
|
||||
- Added the ability to ride Pokémon by shift-right clicking and selecting the ride option.
|
||||
- Added /calculateseatpositions command for approximating hitbox locations for riding configurations.
|
||||
@@ -1,10 +0,0 @@
|
||||
|
||||
### Additions
|
||||
- Added support for NPCs to use Pokémon models and vice versa. This will require changes in addons that add fossil types due to naming conflicts between fossils and the Pokémon species.
|
||||
- Added `/changejointscale` command to change the scale of a joint in a model. Unbelievably funny.
|
||||
|
||||
### Developer
|
||||
- Removed all VaryingModelRepository subclasses into the parent class.
|
||||
|
||||
### Addons
|
||||
- Added `transformedParts` to the root of poser JSONs so it now exists in both poses and the model overall.
|
||||
@@ -1,25 +0,0 @@
|
||||
|
||||
### Additions
|
||||
- Pokémon can now spawn in herds, either as distinct herd groupings or simply several Pokémon spawning at once.
|
||||
|
||||
### Fixes
|
||||
- Fixed the "enabled" property in spawn files not actually being respected. Where do they find these devs?
|
||||
- Fixed Terralith's shrubland not counting as plains for spawning purposes the way it was intended to.
|
||||
|
||||
### Developer
|
||||
- Spawning Influences now have the context of what the other buckets are when adjusting bucket weights. This will break existing influences that do bucket weight adjustment.
|
||||
- Renamed heaps of things in the spawning system to make more sense.
|
||||
- SpawningContext is now SpawnablePosition
|
||||
- WorldSlice is SpawningZone
|
||||
- SpawningProspector is now SpawningZoneGenerator
|
||||
- Majorly refactored the hierarchy of Spawner
|
||||
- The base Spawner interface provides more functions to allow single-point and area spawning given appropriate inputs.
|
||||
- TickingSpawner is removed in favour of outside code handling ticking logic.
|
||||
- AreaSpawner is removed.
|
||||
- BasicSpawner is the first implementation of Spawner which can be used for any purpose.
|
||||
- PlayerSpawners are now mixin'd into ServerPlayer and ticked from ServerPlayer#tick.
|
||||
- A hierarchy diagram can be found at `./docs/spawner-hierarchy.png` in the mod repository.
|
||||
- The SpawnerManager class has been removed as its functionality is all now handled elsewhere.
|
||||
- Renamed things in Spawn Rules to go with the other renames:
|
||||
- contextSelector is now spawnablePositionSelector
|
||||
- context is now spawnable_position
|
||||
+106
-1521
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
# Cobblemon
|
||||
|
||||
An open-source Pokémon mod for Minecraft Java Edition, written in Kotlin for Fabric and NeoForge.
|
||||
An open-source Pokémon mod for Minecraft Java Edition, written in Kotlin for Fabric and Forge.
|
||||
|
||||
## Getting started
|
||||
|
||||
|
||||
@@ -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.
|
||||
+2
-1
@@ -1,10 +1,11 @@
|
||||
plugins {
|
||||
id("cobblemon.root-conventions")
|
||||
id ("net.nemerosa.versioning") version "3.1.0"
|
||||
}
|
||||
|
||||
version = "${project.property("mod_version")}+${project.property("mc_version")}"
|
||||
|
||||
val isSnapshot = project.property("snapshot")?.equals("true") == true
|
||||
val isSnapshot = project.property("snapshot")?.equals("true") ?: false
|
||||
if (isSnapshot) {
|
||||
val fixedBranchName = versioning.info.branch.substringAfter("/")
|
||||
version = "$version-${fixedBranchName}-${versioning.info.build}"
|
||||
|
||||
+5
-12
@@ -1,9 +1,8 @@
|
||||
|
||||
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
|
||||
|
||||
/*
|
||||
*
|
||||
@@ -21,6 +20,7 @@ plugins {
|
||||
|
||||
id("net.kyori.blossom")
|
||||
id("org.jetbrains.gradle.plugin.idea-ext")
|
||||
id("net.nemerosa.versioning") version "3.1.0"
|
||||
}
|
||||
|
||||
architectury {
|
||||
@@ -31,7 +31,6 @@ repositories {
|
||||
maven(url = "${rootProject.projectDir}/deps")
|
||||
maven(url = "https://api.modrinth.com/maven")
|
||||
maven(url = "https://maven.neoforged.net/releases")
|
||||
maven(url = "https://maven.gegy.dev")
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
@@ -42,15 +41,9 @@ dependencies {
|
||||
|
||||
// Integrations
|
||||
compileOnlyApi(libs.jei.api)
|
||||
modCompileOnly(libs.bundles.common.integrations.compileOnly) {
|
||||
modCompileOnly(libs.bundles.fabric.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")
|
||||
}
|
||||
}
|
||||
// Flywheel has no common dep so just pick one and don't use any platform specific code in common
|
||||
// modCompileOnly(libs.flywheelFabric)
|
||||
|
||||
@@ -101,4 +94,4 @@ sourceSets {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common;
|
||||
|
||||
public interface DoubleJump {
|
||||
boolean isDoubleJumping();
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common;
|
||||
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
|
||||
public interface OrientationControllable {
|
||||
OrientationController getOrientationController();
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner;
|
||||
|
||||
/**
|
||||
* Used for mixin shenanigans. ServerPlayers now store their Cobblemon spawner
|
||||
* inside, so this interface helps execute that.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 27th, 2025
|
||||
*/
|
||||
public interface PlayerSpawnerAccessor {
|
||||
PlayerSpawner getPlayerSpawner();
|
||||
void setPlayerSpawner(PlayerSpawner spawner);
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.compat;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonEntities;
|
||||
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokemon.FormData;
|
||||
import com.cobblemon.mod.common.pokemon.lighthing.LightingData;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
import net.minecraft.util.Tuple;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
|
||||
// Java class due to relying on entrypoint on Fabric side
|
||||
public class LambDynamicLightsCompat {
|
||||
|
||||
// This is all called on client side
|
||||
// These things are checked every tick so try to keep it as free as possible
|
||||
// That being said it's unlikely school Toshiba person is running dynamic lighting and shaders to enjoy this
|
||||
// Make sure not to call anything Fabric specific :)
|
||||
public static void hookCompat() {
|
||||
// Pokémon entities
|
||||
// DynamicLightHandlers.registerDynamicLightHandler(
|
||||
// CobblemonEntities.POKEMON,
|
||||
// DynamicLightHandler.makeHandler(
|
||||
// pokemon -> resolvedPokemonLightLevel(pokemon, false),
|
||||
// pokemon -> true
|
||||
// )
|
||||
// );
|
||||
// DynamicLightHandlers.registerDynamicLightHandler(
|
||||
// CobblemonEntities.POKEMON,
|
||||
// DynamicLightHandler.makeHandler(
|
||||
// pokemon -> resolvedPokemonLightLevel(pokemon, true),
|
||||
// pokemon -> false
|
||||
// )
|
||||
// );
|
||||
|
||||
// Shouldered Pokémon
|
||||
// DynamicLightHandlers.registerDynamicLightHandler(
|
||||
// EntityType.PLAYER,
|
||||
// DynamicLightHandler.makeHandler(
|
||||
// player -> resolvedShoulderLightLevel(player, false),
|
||||
// player -> true
|
||||
// )
|
||||
// );
|
||||
// DynamicLightHandlers.registerDynamicLightHandler(
|
||||
// EntityType.PLAYER,
|
||||
// DynamicLightHandler.makeHandler(
|
||||
// player -> resolvedShoulderLightLevel(player, true),
|
||||
// player -> false
|
||||
// )
|
||||
// );
|
||||
}
|
||||
|
||||
private static int resolvedPokemonLightLevel(PokemonEntity pokemon, boolean underwater) {
|
||||
return extractFormLightLevel(pokemon.getForm(), underwater).orElse(0);
|
||||
}
|
||||
|
||||
private static int resolvedShoulderLightLevel(Player player, boolean underwater) {
|
||||
final var shoulderDataPair = PokemonOnShoulderRenderer.shoulderDataOf(player);
|
||||
final Optional<Integer> leftLightLevel = extractShoulderLightLevel(shoulderDataPair.getFirst(), underwater);
|
||||
final Optional<Integer> rightLightLevel = extractShoulderLightLevel(shoulderDataPair.getSecond(), underwater);
|
||||
return Math.max(leftLightLevel.orElse(0), rightLightLevel.orElse(0));
|
||||
}
|
||||
|
||||
private static Optional<Integer> extractFormLightLevel(@NotNull FormData form, boolean underwater) {
|
||||
if (form.getLightingData() == null || !liquidGlowModeSupport(form.getLightingData().getLiquidGlowMode(), underwater)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(form.getLightingData().getLightLevel());
|
||||
}
|
||||
|
||||
private static Optional<Integer> extractShoulderLightLevel(@Nullable PokemonOnShoulderRenderer.ShoulderData shoulderData, boolean underwater) {
|
||||
if (shoulderData == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return extractFormLightLevel(shoulderData.getForm(), underwater);
|
||||
}
|
||||
|
||||
private static boolean liquidGlowModeSupport(@NotNull LightingData.LiquidGlowMode liquidGlowMode, boolean underwater) {
|
||||
return underwater ? liquidGlowMode.getGlowsUnderwater() : liquidGlowMode.getGlowsInLand();
|
||||
}
|
||||
|
||||
}
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.compat.lambdynamiclights;
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.FormData;
|
||||
import com.cobblemon.mod.common.pokemon.lighthing.LightingData;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public abstract class CustomLuminance {
|
||||
protected static Optional<Integer> extractFormLightLevel(@NotNull FormData form, boolean underwater) {
|
||||
if (form.getLightingData() == null || !liquidGlowModeSupport(form.getLightingData().getLiquidGlowMode(), underwater)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(form.getLightingData().getLightLevel());
|
||||
}
|
||||
|
||||
protected static boolean liquidGlowModeSupport(@NotNull LightingData.LiquidGlowMode liquidGlowMode, boolean underwater) {
|
||||
return underwater ? liquidGlowMode.getGlowsUnderwater() : liquidGlowMode.getGlowsInLand();
|
||||
}
|
||||
}
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.compat.lambdynamiclights;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
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.world.entity.EntityType;
|
||||
|
||||
public class LambDynamicLightsInitializer implements DynamicLightsInitializer {
|
||||
public static final EntityLuminance.Type POKEMON_LUMINANCE = EntityLuminance.Type.registerSimple(
|
||||
ResourceLocation.fromNamespaceAndPath(Cobblemon.MODID, "pokemon"),
|
||||
PokemonLuminance.INSTANCE
|
||||
);
|
||||
public static final EntityLuminance.Type PLAYER_LUMINANCE = EntityLuminance.Type.registerSimple(
|
||||
ResourceLocation.fromNamespaceAndPath(Cobblemon.MODID, "shoulder"),
|
||||
PlayerLuminance.INSTANCE
|
||||
);
|
||||
|
||||
@Override
|
||||
public void onInitializeDynamicLights(DynamicLightsContext context) {
|
||||
Cobblemon.LOGGER.info("Lamb Dynamic Lights compatibility enabled");
|
||||
|
||||
context.entityLightSourceManager().onRegisterEvent().register(ctx -> {
|
||||
ctx.register(EntityType.PLAYER, PlayerLuminance.INSTANCE);
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings({"removal", "UnstableApiUsage"})
|
||||
@Override
|
||||
public void onInitializeDynamicLights(ItemLightSourceManager itemLightSourceManager) {}
|
||||
}
|
||||
|
||||
-72
@@ -1,72 +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.compat.lambdynamiclights;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer;
|
||||
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.tags.TagKey;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
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"));
|
||||
|
||||
@Override
|
||||
public @NotNull Type type() {
|
||||
return LambDynamicLightsInitializer.PLAYER_LUMINANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Range(from = 0L, to = 15L) int getLuminance(@NotNull ItemLightSourceManager itemLightSourceManager, @NotNull Entity entity) {
|
||||
if (entity instanceof Player player) {
|
||||
final int shoulderLightLevel = shoulderLuminance(itemLightSourceManager, player);
|
||||
|
||||
final int itemLightLevel = player.isHolding(stack -> stack.is(POKEDEX)) ? 13 : 0;
|
||||
|
||||
return Math.max(shoulderLightLevel, itemLightLevel);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
if (leftShoulder == null && rightShoulder == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
final int leftShoulderLightLevel = extractShoulderLightLevel(leftShoulder, itemLightSourceManager, player.isUnderWater());
|
||||
final int rightShoulderLightLevel = extractShoulderLightLevel(rightShoulder, itemLightSourceManager, player.isUnderWater());
|
||||
return Math.max(leftShoulderLightLevel, rightShoulderLightLevel);
|
||||
}
|
||||
|
||||
private static int extractShoulderLightLevel(@Nullable PokemonOnShoulderRenderer.ShoulderData shoulderData, @NotNull ItemLightSourceManager itemLightSourceManager, boolean underwater) {
|
||||
if (shoulderData == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ItemStack item = shoulderData.getShownItem();
|
||||
int itemLightLevel = item.isEmpty() ? 0 : itemLightSourceManager.getLuminance(item, underwater);
|
||||
int formLightLevel = extractFormLightLevel(shoulderData.getForm(), underwater).orElse(0);
|
||||
|
||||
return Math.max(itemLightLevel, formLightLevel);
|
||||
}
|
||||
}
|
||||
-45
@@ -1,45 +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.compat.lambdynamiclights;
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import dev.lambdaurora.lambdynlights.api.entity.luminance.EntityLuminance;
|
||||
import dev.lambdaurora.lambdynlights.api.item.ItemLightSourceManager;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
public final class PokemonLuminance extends CustomLuminance implements EntityLuminance {
|
||||
public static final PokemonLuminance INSTANCE = new PokemonLuminance();
|
||||
|
||||
private PokemonLuminance() {}
|
||||
|
||||
@Override
|
||||
public @NotNull Type type() {
|
||||
return LambDynamicLightsInitializer.POKEMON_LUMINANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Range(from = 0L, to = 15L) int getLuminance(
|
||||
@NotNull ItemLightSourceManager itemLightSourceManager,
|
||||
@NotNull Entity entity
|
||||
) {
|
||||
if (entity instanceof PokemonEntity pokemon) {
|
||||
boolean underwater = pokemon.isUnderWater();
|
||||
ItemStack item = pokemon.getShownItem();
|
||||
int itemLightLevel = item.isEmpty() ? 0 : itemLightSourceManager.getLuminance(item, underwater);
|
||||
int formLightLevel = extractFormLightLevel(pokemon.getForm(), underwater).orElse(0);
|
||||
|
||||
return Math.max(itemLightLevel, formLightLevel);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
public interface ChannelDuck {
|
||||
void cobblemon$applyLowPassFilter(float gain, float hfGain);
|
||||
void cobblemon$inverseAttenuation(float rolloffFactor);
|
||||
void cobblemon$clearFilters();
|
||||
|
||||
// void cobblemon$exponentialAttenuation(float rolloff, float refDistance, float maxDistance);
|
||||
}
|
||||
@@ -1,18 +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.duck;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
public interface PlayerDuck {
|
||||
void setDriverInput(Vector3f driverInput);
|
||||
Vector3f getDriverInput();
|
||||
void setLastSentDriverInput(Vector3f driverInput);
|
||||
Vector3f getLastSentDriverInput();
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
import net.minecraft.world.item.crafting.RecipeManager;
|
||||
|
||||
public interface RecipeAwareSlot {
|
||||
void setRecipeManager(RecipeManager recipeManager);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public interface RidePassenger {
|
||||
void cobblemon$setRideXRot(float rideXRot);
|
||||
float cobblemon$getRideXRot();
|
||||
void cobblemon$setRideYRot(float rideYRot);
|
||||
float cobblemon$getRideYRot();
|
||||
void cobblemon$setRideEyePos(Vec3 rideEyePos);
|
||||
Vec3 cobblemon$getRideEyePos();
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
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.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
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(AbstractArrow.class)
|
||||
public abstract class AbstractArrowMixin {
|
||||
|
||||
@Inject(
|
||||
method = "<init>(Lnet/minecraft/world/entity/EntityType;Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemStack;)V",
|
||||
at = @At("TAIL")
|
||||
)
|
||||
private void cobblemon$adjustSpawnPosition(
|
||||
EntityType<? extends AbstractArrow> entityType,
|
||||
LivingEntity owner,
|
||||
Level level,
|
||||
ItemStack pickupItemStack,
|
||||
@Nullable ItemStack firedFromWeapon,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
AbstractArrow arrow = (AbstractArrow)(Object)this;
|
||||
if(!(owner.getVehicle() instanceof OrientationControllable vehicle)) return;
|
||||
if(!(vehicle instanceof PokemonEntity)) return;
|
||||
var vehicleController = vehicle.getOrientationController();
|
||||
|
||||
// If this is a pokemon ride passenger then use the rider eye position to set the arrow spawn position.
|
||||
if (owner instanceof RidePassenger ridePassenger && vehicleController != null ) {
|
||||
var eyePos = ridePassenger.cobblemon$getRideEyePos(); //.add(0.0, -2.0, 0.0);
|
||||
arrow.setPos(eyePos);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +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.SaccharineLeafBlock;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
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.ModifyVariable;
|
||||
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")
|
||||
public abstract class BeeEntityMixin {
|
||||
|
||||
@Unique
|
||||
private BlockState cobblemon$result = null;
|
||||
|
||||
@Inject(method = "tick()V", 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,
|
||||
by = 2
|
||||
),
|
||||
locals = LocalCapture.CAPTURE_FAILHARD
|
||||
)
|
||||
private void injectCustomGrowth(CallbackInfo ci, int i, BlockPos blockPos, BlockState blockState, Block block) {
|
||||
if (block instanceof SaccharineLeafBlock) {
|
||||
|
||||
int age = blockState.getValue(SaccharineLeafBlock.Companion.getAGE());
|
||||
boolean waterlogged = blockState.getValue(BlockStateProperties.WATERLOGGED);
|
||||
|
||||
if (age < 2 && !waterlogged) {
|
||||
this.cobblemon$result = blockState.setValue(SaccharineLeafBlock.Companion.getAGE(), age + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ModifyVariable(method = "tick", at = @At(value = "LOAD", ordinal = 0), index = 5)
|
||||
private BlockState applyCustomBlockState(BlockState before) {
|
||||
if(this.cobblemon$result != null && before == null) {
|
||||
BlockState result = this.cobblemon$result;
|
||||
this.cobblemon$result = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
return before;
|
||||
}
|
||||
}
|
||||
@@ -1,107 +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.CobblemonMemories;
|
||||
import com.cobblemon.mod.common.api.ai.config.task.PathToBeeHiveTaskConfig;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.item.component.CustomData;
|
||||
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.phys.Vec3;
|
||||
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.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Mixin(BeehiveBlockEntity.Occupant.class)
|
||||
public abstract class BeeOccupantMixin {
|
||||
|
||||
@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();
|
||||
Entity entity = EntityType.loadEntityRecursive(compoundTag, level, (entityx) -> entityx);
|
||||
if (entity instanceof PokemonEntity pokemonEntity) {
|
||||
var state = level.getBlockState(pos);
|
||||
var newPos = Vec3.ZERO;
|
||||
var newYaw = 0f;
|
||||
var brain = pokemonEntity.getBrain();
|
||||
if (state.is(BlockTags.BEEHIVES)) {
|
||||
// position in front of the entrance, face away from the block
|
||||
var facing = state.getValue(HorizontalDirectionalBlock.FACING);
|
||||
newPos = pos.relative(facing).getCenter();
|
||||
newYaw = facing.toYRot();
|
||||
brain.setMemory(CobblemonMemories.INSTANCE.getHIVE_LOCATION(), pos); // This needs to be set in the case that the hive was picked up and moved.
|
||||
} else {
|
||||
// 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
|
||||
);
|
||||
newYaw = level.random.nextFloat() * 360F;
|
||||
brain.eraseMemory(CobblemonMemories.INSTANCE.getHIVE_LOCATION());
|
||||
}
|
||||
entity.yRotO = newYaw;
|
||||
entity.setPos(newPos);
|
||||
// Do honey logic
|
||||
var hasNectar = brain.getMemory(CobblemonMemories.INSTANCE.getHAS_NECTAR()).orElse(false);
|
||||
if (hasNectar) {
|
||||
// Remove nectar and reset got to hive cooldown
|
||||
brain.eraseMemory(CobblemonMemories.INSTANCE.getHAS_NECTAR());
|
||||
brain.setMemoryWithExpiry(CobblemonMemories.INSTANCE.getHIVE_COOLDOWN(), true, PathToBeeHiveTaskConfig.STAY_OUT_OF_HIVE_COOLDOWN);
|
||||
// Increment honey level of the hive
|
||||
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;
|
||||
if (i + j > 5) {
|
||||
--j;
|
||||
}
|
||||
level.setBlockAndUpdate(pos, state.setValue(BeehiveBlock.HONEY_LEVEL, i + j));
|
||||
}
|
||||
}
|
||||
}
|
||||
cir.setReturnValue(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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", "Brain", "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().getMemory(CobblemonMemories.INSTANCE.getHAS_NECTAR()).orElse(false);
|
||||
cir.setReturnValue(new BeehiveBlockEntity.Occupant(CustomData.of(compoundTag), 0, hasNectar ? 2400 : 600));
|
||||
cir.cancel();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,102 +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 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;
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
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 java.util.List;
|
||||
|
||||
@Mixin(BeehiveBlockEntity.class)
|
||||
public abstract class BeehiveBlockEntityMixin {
|
||||
|
||||
|
||||
// Accessor for the private 'stored' field in BeehiveBlockEntity
|
||||
@Accessor("stored")
|
||||
public abstract List<BeeDataAccessor> getStored();
|
||||
|
||||
@Inject(method = "emptyAllLivingFromHive", at = @At("HEAD"))
|
||||
private void cobblemon$emptyAllLivingFromHive(@Nullable Player player, BlockState state, BeehiveBlockEntity.BeeReleaseStatus releaseStatus, CallbackInfo ci) {
|
||||
if (player != null) {
|
||||
final BeehiveBlockEntity blockEntity = (BeehiveBlockEntity) (Object) this;
|
||||
// if the block is sedated or the player is too far away, no aggro should be applied
|
||||
if (blockEntity.isSedated() || player.position().distanceToSqr(blockEntity.getBlockPos().getCenter()) > 16.0)
|
||||
return;
|
||||
// from this point need to access private members of the block entity
|
||||
final BeehiveBlockEntityAccessor blockEntityAccessor = (BeehiveBlockEntityAccessor) this;
|
||||
List<Object> storedList = blockEntityAccessor.getStored();
|
||||
|
||||
List<Entity> list = Lists.newArrayList();
|
||||
storedList.removeIf((beeData) -> {
|
||||
BeehiveBlockEntity.Occupant occupant = ((BeeDataAccessor) beeData).invokeToOccupant();
|
||||
// Checking the for the tag allows us to make sure it's one of our pokemon before trying to rehydrate it into an entity
|
||||
boolean isPokemon = false;
|
||||
if (occupant.entityData().contains("id")) {
|
||||
isPokemon = "cobblemon:pokemon".equals(occupant.entityData().getUnsafe().getString("id"));
|
||||
}
|
||||
if (isPokemon) {
|
||||
return BeehiveBlockEntityAccessor.releaseOccupant(
|
||||
((BlockEntityAccessor) blockEntityAccessor).getLevel(),
|
||||
((BlockEntityAccessor) blockEntityAccessor).getWorldPosition(),
|
||||
state,
|
||||
occupant,
|
||||
list,
|
||||
releaseStatus,
|
||||
blockEntityAccessor.savedFlowerPos());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
);
|
||||
for (Entity entity : list) {
|
||||
if (entity instanceof PokemonEntity) {
|
||||
((PokemonEntity) entity).getBrain().setMemory(MemoryModuleType.ATTACK_TARGET, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
method = "releaseOccupant",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/level/Level;addFreshEntity(Lnet/minecraft/world/entity/Entity;)Z"
|
||||
)
|
||||
)
|
||||
private static boolean cobblemon$captureReleasedEntity(
|
||||
Level level, Entity entity,
|
||||
Level lvl, BlockPos pos, BlockState state,
|
||||
BeehiveBlockEntity.Occupant occupant, @Nullable List<Entity> bees,
|
||||
BeehiveBlockEntity.BeeReleaseStatus releaseStatus, @Nullable BlockPos flowerPos) {
|
||||
|
||||
if (bees != null && !bees.contains(entity)) {
|
||||
// Avoid duplicates if vanilla also adds bees to the list on your version
|
||||
bees.add(entity);
|
||||
}
|
||||
return level.addFreshEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,70 +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.duck.ChannelDuck;
|
||||
import com.mojang.blaze3d.audio.Channel;
|
||||
import org.lwjgl.openal.AL10;
|
||||
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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,4 +45,21 @@ public class ChunkStorageMixin {
|
||||
int curVersion = vanillaFixed.contains(VERSION_KEY) ? vanillaFixed.getInt(VERSION_KEY) : 0;
|
||||
return DataFixTypes.CHUNK.update(CobblemonSchemas.getDATA_FIXER(), vanillaFixed, curVersion, CobblemonSchemas.DATA_VERSION);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
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/nbt/NbtUtils;addCurrentDataVersion(Lnet/minecraft/nbt/CompoundTag;)Lnet/minecraft/nbt/CompoundTag;"
|
||||
)
|
||||
)
|
||||
public void cobblemon$addChunkVersion(
|
||||
ResourceKey<Level> resourceKey,
|
||||
Supplier<DimensionDataStorage> supplier,
|
||||
CompoundTag compoundTag,
|
||||
Optional<ResourceKey<MapCodec<? extends ChunkGenerator>>> optional,
|
||||
CallbackInfoReturnable<CompoundTag> cir
|
||||
) {
|
||||
compoundTag.put(VERSION_KEY, IntTag.valueOf(CobblemonSchemas.DATA_VERSION));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||
import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
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.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
@Mixin(ClientPacketListener.class)
|
||||
public class ClientPacketListenerMixin {
|
||||
|
||||
@Shadow private ClientLevel level;
|
||||
|
||||
@Inject(method = "handleSetEntityPassengersPacket", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/world/entity/Entity;hasIndirectPassenger(Lnet/minecraft/world/entity/Entity;)Z", shift = At.Shift.BEFORE), cancellable = true)
|
||||
private void cobblemon$handlePokemonPassengers(ClientboundSetPassengersPacket packet, CallbackInfo ci) {
|
||||
Entity entity = this.level.getEntity(packet.getVehicle());
|
||||
if (entity instanceof PokemonEntity pokemon) {
|
||||
var passengers = new ArrayList<Entity>();
|
||||
for (int passenger : packet.getPassengers()) {
|
||||
passengers.add(this.level.getEntity(passenger));
|
||||
}
|
||||
Arrays
|
||||
.stream(pokemon.getOccupiedSeats())
|
||||
.filter(x -> !passengers.contains(x))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(Entity::stopRiding);
|
||||
|
||||
var occupiedSeats = Arrays.asList(pokemon.getOccupiedSeats());
|
||||
passengers.stream()
|
||||
.filter(x -> !occupiedSeats.contains(x))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(x -> x.startRiding(pokemon, true));
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,62 +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.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResultHolder;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.EnderpearlItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
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.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) {
|
||||
double range = player.entityInteractionRange();
|
||||
Entity closestEntity = level.getEntities(player, AABB.ofSize(player.position(), range, range, range)).stream()
|
||||
.filter(entity -> isLookingAt(player, entity))
|
||||
.min(Comparator.comparingDouble(entity -> entity.distanceTo(player)))
|
||||
.orElse(null);
|
||||
|
||||
if (closestEntity instanceof PokemonEntity pokemonEntity) {
|
||||
if (player.isCrouching() && pokemonEntity.getOwnerUUID() == player.getUUID()) {
|
||||
cir.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isLookingAt(Player player, Entity other) {
|
||||
float maxDistance = 10F;
|
||||
float stepDistance = 0.1F;
|
||||
double step = stepDistance;
|
||||
Vec3 startPos = player.getEyePosition();
|
||||
Vec3 direction = player.getLookAngle();
|
||||
|
||||
while (step <= maxDistance) {
|
||||
Vec3 location = startPos.add(direction.scale(step));
|
||||
step += stepDistance;
|
||||
|
||||
if (other.getBoundingBox().contains(location)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,61 +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 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.monster.Creeper;
|
||||
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(Creeper.class)
|
||||
public class EntityCreeperMixin extends Mob {
|
||||
|
||||
private EntityCreeperMixin(net.minecraft.world.entity.EntityType<? extends Creeper> entityType, Level world) {
|
||||
super(entityType, world);
|
||||
}
|
||||
|
||||
@Inject(method = "registerGoals", at = @At(value = "TAIL"), cancellable = false)
|
||||
private void cobblemon$initGoals(CallbackInfo callbackInfo) {
|
||||
final Creeper creeper = (Creeper) (Object) this;
|
||||
// Pokemon Entities
|
||||
this.goalSelector.addGoal(
|
||||
3,
|
||||
new AvoidEntityGoal<>(
|
||||
creeper,
|
||||
PokemonEntity.class,
|
||||
6.0f,
|
||||
1.0,
|
||||
1.2,
|
||||
entity -> ((PokemonEntity)entity).getBehaviour().getEntityInteract().getAvoidedByCreeper() && ((PokemonEntity)entity).getBeamMode() != 1
|
||||
)
|
||||
);
|
||||
|
||||
// Players with shoulder mounted Pokemon
|
||||
this.goalSelector.addGoal(
|
||||
3,
|
||||
new AvoidEntityGoal<>(
|
||||
creeper,
|
||||
ServerPlayer.class,
|
||||
6.0f,
|
||||
1.0,
|
||||
1.2,
|
||||
entity -> EntityBehaviour.Companion.hasCreeperFearedShoulderMount((ServerPlayer)entity)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,62 +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 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.monster.Creeper;
|
||||
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(Fox.class)
|
||||
public class EntityFoxMixin extends Mob {
|
||||
|
||||
private EntityFoxMixin(net.minecraft.world.entity.EntityType<? extends Creeper> entityType, Level world) {
|
||||
super(entityType, world);
|
||||
}
|
||||
|
||||
@Inject(method = "registerGoals", at = @At(value = "TAIL"), cancellable = false)
|
||||
private void cobblemon$initGoals(CallbackInfo callbackInfo) {
|
||||
final Fox fox = (Fox) (Object) this;
|
||||
// Pokemon Entities
|
||||
this.goalSelector.addGoal(
|
||||
4,
|
||||
new AvoidEntityGoal<>(
|
||||
fox,
|
||||
PokemonEntity.class,
|
||||
8.0f,
|
||||
1.6,
|
||||
1.4,
|
||||
entity -> ((PokemonEntity)entity).getBehaviour().getEntityInteract().getAvoidedByFox() && ((PokemonEntity)entity).getBeamMode() != 1
|
||||
)
|
||||
);
|
||||
|
||||
// Players with shoulder mounted Pokemon
|
||||
this.goalSelector.addGoal(
|
||||
3,
|
||||
new AvoidEntityGoal<>(
|
||||
fox,
|
||||
ServerPlayer.class,
|
||||
8.0f,
|
||||
1.6,
|
||||
1.4,
|
||||
entity -> EntityBehaviour.Companion.hasFoxFearedShoulderMount((ServerPlayer)entity)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+5
-65
@@ -9,19 +9,6 @@
|
||||
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.renderer.entity.EntityRenderDispatcher;
|
||||
import net.minecraft.client.renderer.entity.EntityRenderer;
|
||||
import net.minecraft.client.resources.PlayerSkin;
|
||||
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 org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
@@ -29,6 +16,11 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.Map;
|
||||
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
|
||||
import net.minecraft.client.renderer.entity.EntityRenderer;
|
||||
import net.minecraft.client.resources.PlayerSkin;
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
|
||||
@Mixin(EntityRenderDispatcher.class)
|
||||
public class EntityRenderDispatcherMixin {
|
||||
@@ -42,56 +34,4 @@ public class EntityRenderDispatcherMixin {
|
||||
public void resourceManagerReloadHook(ResourceManager resourceManager, CallbackInfo ci) {
|
||||
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();
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +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 com.cobblemon.mod.common.pokemon.ai.EntityBehaviour;
|
||||
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.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(AbstractSkeleton.class)
|
||||
public class EntitySkeletonMixin extends Mob {
|
||||
|
||||
private EntitySkeletonMixin(EntityType<? extends Mob> entityType, Level world) {
|
||||
super(entityType, world);
|
||||
}
|
||||
|
||||
@Inject(method = "registerGoals", at = @At(value = "TAIL"))
|
||||
private void cobblemon$initGoals(CallbackInfo callbackInfo) {
|
||||
final AbstractSkeleton skeleton = (AbstractSkeleton) (Object) this;
|
||||
// Pokemon Entities
|
||||
this.goalSelector.addGoal(
|
||||
3,
|
||||
new AvoidEntityGoal<>(
|
||||
skeleton,
|
||||
PokemonEntity.class,
|
||||
6.0f,
|
||||
1.0,
|
||||
1.2,
|
||||
entity -> ((PokemonEntity)entity).getBehaviour().getEntityInteract().getAvoidedBySkeleton() && ((PokemonEntity)entity).getBeamMode() != 1
|
||||
)
|
||||
);
|
||||
|
||||
// Players with shoulder mounted Pokemon
|
||||
this.goalSelector.addGoal(
|
||||
3,
|
||||
new AvoidEntityGoal<>(
|
||||
skeleton,
|
||||
ServerPlayer.class,
|
||||
6.0f,
|
||||
1.0,
|
||||
1.2,
|
||||
entity -> EntityBehaviour.Companion.hasSkeletonFearedShoulderMount((ServerPlayer)entity)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ public abstract class EntityVillagerMixin {
|
||||
@Inject(method = "wantsToPickUp", at = @At(value = "RETURN"), cancellable = true)
|
||||
private void cobblemon$canGather(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() == false && Objects.equals(villager.getVillagerData().getProfession(), 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.api.scheduling.ClientTaskTracker;
|
||||
import net.minecraft.client.DeltaTracker;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(GameRenderer.class)
|
||||
public class GameRendererMixin {
|
||||
@Unique
|
||||
long lastTime = -1;
|
||||
|
||||
@Inject(
|
||||
method = "render",
|
||||
at = @At(value = "TAIL")
|
||||
)
|
||||
public void render(DeltaTracker counter, boolean tick, CallbackInfo ci) {
|
||||
Minecraft client = Minecraft.getInstance();
|
||||
long newTime = System.currentTimeMillis();
|
||||
// Don't play scheduled animations when the game is paused
|
||||
if (client.isPaused()) {
|
||||
lastTime = newTime;
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastTime != -1) {
|
||||
ClientTaskTracker.INSTANCE.update((newTime - lastTime) / 1000F);
|
||||
}
|
||||
lastTime = newTime;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.item.PokedexItem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.ItemInHandRenderer;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.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(ItemInHandRenderer.class)
|
||||
public class ItemInHandRendererMixin {
|
||||
@Inject(method = "renderArmWithItem", at = @At(value = "HEAD"), cancellable = true)
|
||||
private void cobblemon$renderArmWithItem(AbstractClientPlayer abstractClientPlayer, float f, float g, InteractionHand interactionHand, float h, ItemStack itemStack, float i, PoseStack poseStack, MultiBufferSource multiBufferSource, int j, CallbackInfo ci) {
|
||||
if (abstractClientPlayer.isUsingItem() && abstractClientPlayer.getUseItem().getItem() instanceof PokedexItem) {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.ModAPI;
|
||||
import com.cobblemon.mod.common.client.CobblemonBakingOverrides;
|
||||
import com.cobblemon.mod.common.item.PokeBallItem;
|
||||
import com.cobblemon.mod.common.item.PokedexItem;
|
||||
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.world.entity.LivingEntity;
|
||||
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 {
|
||||
@Unique private final String MODEL_PATH = 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;
|
||||
if (!shouldBe2d && stack.getItem() instanceof PokedexItem) {
|
||||
BakedModel replacementModel = CobblemonBakingOverrides.INSTANCE.getPokedexOverride(((PokedexItem) stack.getItem()).getType()).getModel();
|
||||
if (!cobblemon$isSameModel(model, replacementModel)) {
|
||||
ci.cancel();
|
||||
render(stack, renderMode, leftHanded, matrices, multiBufferSource, light, overlay, replacementModel);
|
||||
}
|
||||
} else if (shouldBe2d && stack.getItem() instanceof PokeBallItem pokeBallItem) {
|
||||
BakedModel replacementModel = this.itemModelShaper.getModelManager().getModel(new ModelResourceLocation(pokeBallItem.getPokeBall().getModel2d(), "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$bakePokeballModel(ItemStack stack, Level world, LivingEntity entity, int seed, CallbackInfoReturnable<BakedModel> cir) {
|
||||
if (stack.getItem() instanceof PokeBallItem pokeBallItem) {
|
||||
BakedModel model = this.itemModelShaper.getModelManager().getModel(new ModelResourceLocation(pokeBallItem.getPokeBall().getModel3d(), 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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -52,11 +52,10 @@ 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);
|
||||
} else {
|
||||
cir.setReturnValue(itemStack.isEmpty() && interactionHand == InteractionHand.MAIN_HAND ? ItemInteractionResult.SKIP_DEFAULT_BLOCK_INTERACTION : ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION);
|
||||
}
|
||||
|
||||
world.playSound(null, blockPos, CobblemonSounds.POKEDEX_CLOSE, SoundSource.BLOCKS, 0.5F, 1.25F);
|
||||
cir.setReturnValue(itemStack.isEmpty() && interactionHand == InteractionHand.MAIN_HAND ? ItemInteractionResult.SKIP_DEFAULT_BLOCK_INTERACTION : ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +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.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LightningBolt;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Mixin(LightningBolt.class)
|
||||
public abstract class LightningBoltMixin {
|
||||
|
||||
@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;
|
||||
List<Entity> list = lightningBolt.level().getEntities(
|
||||
lightningBolt,
|
||||
new AABB(lightningBolt.getX() - 2.0, lightningBolt.getY() - 2.0, lightningBolt.getZ() - 2.0, lightningBolt.getX() + 2.0, lightningBolt.getY() + 2.0, lightningBolt.getZ() + 2.0),
|
||||
it -> {
|
||||
if (!it.isAlive() || !(it instanceof PokemonEntity)) {
|
||||
return false;
|
||||
}
|
||||
String abilityName = ((PokemonEntity) it).getPokemon().getAbility().getName();
|
||||
return abilityName.equals("lightningrod") || abilityName.equals("voltabsorb") || abilityName.equals("motordrive");
|
||||
});
|
||||
if (!list.isEmpty()) {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,52 +8,17 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.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.client.entity.PokemonClientDelegate;
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper;
|
||||
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.server.level.ServerPlayer;
|
||||
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.level.ClipContext;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
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;
|
||||
|
||||
@Mixin(LivingEntity.class)
|
||||
public abstract class LivingEntityMixin extends Entity implements OrientationControllable {
|
||||
|
||||
public LivingEntityMixin(EntityType<?> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private final OrientationController cobblemon$orientationController = new OrientationController((LivingEntity) (Object) this);
|
||||
|
||||
public OrientationController getOrientationController() {
|
||||
return cobblemon$orientationController;
|
||||
}
|
||||
public abstract class LivingEntityMixin {
|
||||
|
||||
@Inject(method = "onEffectRemoved", at = @At(value = "TAIL"))
|
||||
private void cobblemon$onEffectRemoved(MobEffectInstance effect, CallbackInfo ci) {
|
||||
@@ -63,100 +28,4 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
|
||||
}
|
||||
}
|
||||
|
||||
@WrapOperation(method = "baseTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;isInWall()Z"))
|
||||
public boolean cobblemon$preventMountSuffocation(LivingEntity instance, Operation<Boolean> original) {
|
||||
if (instance.getVehicle() instanceof PokemonEntity) {
|
||||
return false;
|
||||
}
|
||||
return original.call(instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HitResult pick(double hitDistance, float partialTicks, boolean hitFluids) {
|
||||
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());
|
||||
|
||||
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
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return super.pick(hitDistance, partialTicks, hitFluids);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private Vec3 cobblemon$getEyePosition(float partialTicks, PokemonEntity pokemonEntity, Vec3 locatorOffset) {
|
||||
OrientationController controller = this.getOrientationController();
|
||||
|
||||
float currEyeHeight = this.getEyeHeight();
|
||||
Vec3 offset = locatorOffset.add(pokemonEntity.position());
|
||||
if (controller.isActive() && controller.getOrientation() != null) {
|
||||
Quaternionf orientation = controller.getRenderOrientation(partialTicks);
|
||||
Vec3 rotatedEyeHeight = new Vec3(orientation.transform(new Vector3f(0f, currEyeHeight - (this.getBbHeight() / 2), 0f)));
|
||||
|
||||
offset.add(rotatedEyeHeight);
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("HEAD"))
|
||||
private void cobblemon$updateRenderOrientation(CallbackInfo ci) {
|
||||
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,
|
||||
CallbackInfoReturnable<Integer> cir
|
||||
) {
|
||||
var entity = (LivingEntity) (Object) this;
|
||||
if (!(entity instanceof Player player)) return;
|
||||
if (!(player.getVehicle() instanceof PokemonEntity vehicle)) return;
|
||||
|
||||
var ridingController = vehicle.getRidingController();
|
||||
if (ridingController == null) return;
|
||||
|
||||
var activeContext = ridingController.getContext();
|
||||
if (activeContext == null) return;
|
||||
|
||||
// If the rider is currently on a submarine and the ride still has stamina.
|
||||
var stamina = activeContext.getState().getStamina().get();
|
||||
if (
|
||||
activeContext.getStyle() == RidingStyle.LIQUID &&
|
||||
activeContext.getBehaviour().equals(SubmarineBehaviour.Companion.getKEY()) &&
|
||||
stamina > 0.0f
|
||||
) {
|
||||
cir.setReturnValue(currentAir);
|
||||
cir.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ 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) {
|
||||
if(entity instanceof PokemonEntity) {
|
||||
callback.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.client.CobblemonBakingOverrides;
|
||||
import java.util.List;
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Bone;
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.RenderContext;
|
||||
@@ -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 static com.cobblemon.mod.common.datafixer.CobblemonSchemas.VERSION_KEY;
|
||||
|
||||
import com.cobblemon.mod.common.datafixer.CobblemonSchemas;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
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(NbtUtils.class)
|
||||
public class NbtUtilsMixin {
|
||||
@Inject(
|
||||
method = "addCurrentDataVersion(Lnet/minecraft/nbt/CompoundTag;)Lnet/minecraft/nbt/CompoundTag;",
|
||||
at = @At("TAIL")
|
||||
)
|
||||
private static void addCobblemonDataVersion(
|
||||
CompoundTag tag,
|
||||
CallbackInfoReturnable<CompoundTag> cir
|
||||
) {
|
||||
tag.putInt(VERSION_KEY, CobblemonSchemas.DATA_VERSION);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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.CobblemonClient;
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding;
|
||||
import com.cobblemon.mod.common.item.PokedexItem;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.MouseHandler;
|
||||
import net.minecraft.util.Mth;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(MouseHandler.class)
|
||||
public class PartyScrollMixin {
|
||||
@Shadow
|
||||
private double accumulatedScrollY;
|
||||
|
||||
@Shadow @Final private Minecraft minecraft;
|
||||
|
||||
@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();
|
||||
} else if (i < 0) {
|
||||
accumulatedScrollY -= i;
|
||||
CobblemonClient.INSTANCE.getStorage().shiftSelected(true);
|
||||
ci.cancel();
|
||||
PartySendBinding.INSTANCE.actioned();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,57 +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 com.cobblemon.mod.common.pokemon.ai.EntityBehaviour;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.ai.goal.Goal;
|
||||
import net.minecraft.world.entity.monster.Phantom;
|
||||
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;
|
||||
|
||||
|
||||
|
||||
@Mixin(targets = "net.minecraft.world.entity.monster.Phantom$PhantomSweepAttackGoal")
|
||||
public abstract class PhantomSweepAttackGoalMixin extends Goal {
|
||||
|
||||
@Unique
|
||||
private Phantom phantomSelf; // Allows access to the outer class
|
||||
|
||||
@Inject(method = "<init>", at = @At("TAIL"))
|
||||
private void onInit(Phantom phantom, CallbackInfo ci) {
|
||||
this.phantomSelf = phantom;
|
||||
}
|
||||
|
||||
@Inject(method = "canContinueToUse", at = @At("RETURN"), cancellable = true)
|
||||
private void modifyCanContinueToUse(CallbackInfoReturnable<Boolean> cir) {
|
||||
Phantom phantom = this.phantomSelf; // Outer class instance
|
||||
if(phantom == null) return;
|
||||
|
||||
if (cir.getReturnValue()) {
|
||||
var nearbyFearedEntities = phantom.level().getEntities(phantom, phantom.getBoundingBox().inflate(16.0),
|
||||
(entity -> ((entity instanceof PokemonEntity && ((PokemonEntity) entity).getBeamMode() == 0 && ((PokemonEntity) entity).getBehaviour().getEntityInteract().getAvoidedByPhantom())
|
||||
|| (entity instanceof ServerPlayer && EntityBehaviour.Companion.hasPhantomFearedShoulderMount((ServerPlayer)entity)))));
|
||||
if (!nearbyFearedEntities.isEmpty()) {
|
||||
nearbyFearedEntities.forEach(entity -> {
|
||||
if (entity instanceof PokemonEntity) {
|
||||
((PokemonEntity) entity).cry();
|
||||
}
|
||||
//TODO: Find a way to make shoulder mounted Pokemon cry
|
||||
});
|
||||
cir.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,9 @@ public class PiglinBarterMixin {
|
||||
|
||||
@Inject(method = "isBarterCurrency", at = @At(value = "RETURN"), cancellable = true)
|
||||
private static void cobblemon$acceptsForBarter(ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
|
||||
if (!ci.getReturnValue()) {
|
||||
if(!ci.getReturnValue()) {
|
||||
//TODO: Make a tag?
|
||||
if (stack.is(CobblemonItems.RELIC_COIN_POUCH))
|
||||
if(stack.is(CobblemonItems.RELIC_COIN_POUCH))
|
||||
ci.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.platform.events.PlatformEvents;
|
||||
import com.cobblemon.mod.common.platform.events.ServerPlayerEvent;
|
||||
import net.minecraft.advancements.AdvancementHolder;
|
||||
import net.minecraft.server.PlayerAdvancements;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(PlayerAdvancements.class)
|
||||
public class PlayerAdvancementsMixin {
|
||||
@Shadow private ServerPlayer player;
|
||||
|
||||
@Inject(method = "award", at = @At(value = "INVOKE", target = "Lnet/minecraft/advancements/AdvancementRewards;grant(Lnet/minecraft/server/level/ServerPlayer;)V"))
|
||||
private void cobblemon$award(AdvancementHolder advancement, String criterionKey, CallbackInfoReturnable<Boolean> cir) {
|
||||
PlatformEvents.SERVER_PLAYER_ADVANCEMENT_EARNED.emit(new ServerPlayerEvent.AdvancementEarned(player, advancement));
|
||||
}
|
||||
}
|
||||
@@ -10,67 +10,39 @@ package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
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.storage.NoPokemonStoreException;
|
||||
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;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexEntityData;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.ScannableEntity;
|
||||
import com.cobblemon.mod.common.pokemon.FormData;
|
||||
import com.cobblemon.mod.common.pokemon.Gender;
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon;
|
||||
import com.cobblemon.mod.common.pokemon.Species;
|
||||
import com.cobblemon.mod.common.util.CompoundTagExtensionsKt;
|
||||
import com.cobblemon.mod.common.util.CompoundTagUtilities;
|
||||
import com.cobblemon.mod.common.util.DataKeys;
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.entity.EntityDimensions;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.Pose;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.food.FoodProperties;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
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;
|
||||
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.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
@Mixin(Player.class)
|
||||
public abstract class PlayerMixin extends LivingEntity implements ScannableEntity, OrientationControllable, PlayerDuck, RidePassenger {
|
||||
|
||||
@Unique
|
||||
private Vector3f cobblemon$driverInput;
|
||||
@Unique
|
||||
private Vector3f cobblemon$lastSentDriverInput;
|
||||
public abstract class PlayerMixin extends LivingEntity {
|
||||
|
||||
@Shadow public abstract CompoundTag getShoulderEntityLeft();
|
||||
|
||||
@@ -88,16 +60,6 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
|
||||
@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);
|
||||
|
||||
@Unique private float cobblemon$rideXRot = 0.0f;
|
||||
|
||||
@Unique private float cobblemon$rideYRot = 0.0f;
|
||||
|
||||
@Unique private Vec3 cobblemon$rideEyePos = Vec3.ZERO;
|
||||
|
||||
protected PlayerMixin(EntityType<? extends LivingEntity> p_20966_, Level p_20967_) {
|
||||
super(p_20966_, p_20967_);
|
||||
@@ -106,16 +68,16 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
@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());
|
||||
final UUID uuid = this.getPokemonID(nbt);
|
||||
if (this.isShoulderPokemon(this.getShoulderEntityRight())) {
|
||||
final UUID uuidRight = this.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 (this.isShoulderPokemon(this.getShoulderEntityLeft())) {
|
||||
final UUID uuidLeft = this.getPokemonID(this.getShoulderEntityLeft());
|
||||
if (uuid.equals(uuidLeft)) {
|
||||
this.recallPokemon(uuidLeft);
|
||||
this.setShoulderEntityLeft(new CompoundTag());
|
||||
@@ -125,14 +87,6 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityDimensions getDefaultDimensions(Pose pose) {
|
||||
if (this.getVehicle() instanceof PokemonEntity) {
|
||||
return STANDING_DIMENSIONS;
|
||||
}
|
||||
return POSES.getOrDefault(pose, STANDING_DIMENSIONS);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "removeEntitiesOnShoulder",
|
||||
at = @At(
|
||||
@@ -147,17 +101,22 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
// We want to allow both of these to forcefully remove the entities
|
||||
if (this.isSpectator() || this.isDeadOrDying())
|
||||
return;
|
||||
if (!CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityLeft())) {
|
||||
if (!this.isShoulderPokemon(this.getShoulderEntityLeft())) {
|
||||
this.respawnEntityOnShoulder(this.getShoulderEntityLeft());
|
||||
this.setShoulderEntityLeft(new CompoundTag());
|
||||
}
|
||||
if (!CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityRight())) {
|
||||
if (!this.isShoulderPokemon(this.getShoulderEntityRight())) {
|
||||
this.respawnEntityOnShoulder(this.getShoulderEntityRight());
|
||||
this.setShoulderEntityRight(new CompoundTag());
|
||||
}
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
private UUID getPokemonID(CompoundTag nbt) {
|
||||
return nbt.getCompound(DataKeys.POKEMON)
|
||||
.getUUID(DataKeys.POKEMON_UUID);
|
||||
}
|
||||
|
||||
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());
|
||||
@@ -168,6 +127,10 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isShoulderPokemon(CompoundTag nbt) {
|
||||
return CompoundTagExtensionsKt.isPokemonEntity(nbt);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "eat",
|
||||
at = @At(
|
||||
@@ -199,7 +162,8 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
|
||||
@Inject(method = "isInvulnerableTo", at = @At("HEAD"), cancellable = true)
|
||||
public void isInvulnerableTo(DamageSource source, CallbackInfoReturnable<Boolean> ci) {
|
||||
if (!level().isClientSide && (Object) this instanceof ServerPlayer player) {
|
||||
if (!level().isClientSide) {
|
||||
ServerPlayer player = (ServerPlayer)(Object)this;
|
||||
boolean invulnerableInBattle = this.level().getGameRules().getBoolean(CobblemonGameRules.BATTLE_INVULNERABILITY);
|
||||
boolean inBattle = Cobblemon.INSTANCE.getBattleRegistry().getBattleByParticipatingPlayer(player) != null;
|
||||
if (invulnerableInBattle && inBattle) {
|
||||
@@ -207,137 +171,4 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override @Nullable
|
||||
public PokedexEntityData resolvePokemonScan() {
|
||||
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityRight())){
|
||||
return getDataFromShoulderPokemon(this.getShoulderEntityRight());
|
||||
}
|
||||
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityLeft())){
|
||||
return getDataFromShoulderPokemon(this.getShoulderEntityLeft());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable @Unique
|
||||
private PokedexEntityData getDataFromShoulderPokemon(CompoundTag shoulderTag) {
|
||||
CompoundTag pokemonTag = shoulderTag.getCompound(DataKeys.POKEMON);
|
||||
if (pokemonTag.isEmpty()) return null;
|
||||
Species species = PokemonSpecies.INSTANCE.getByIdentifier(ResourceLocation.parse(pokemonTag.getString(DataKeys.POKEMON_SPECIES_IDENTIFIER)));
|
||||
if (species == null) return null;
|
||||
String formId = pokemonTag.getString(DataKeys.POKEMON_FORM_ID);
|
||||
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);
|
||||
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());
|
||||
|
||||
Pokemon pokemon = new Pokemon();
|
||||
if (level().isClientSide) {
|
||||
pokemon.setSpecies(species);
|
||||
pokemon.setForm(form);
|
||||
pokemon.setGender(gender);
|
||||
pokemon.setShiny(shiny);
|
||||
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));
|
||||
}
|
||||
return new PokedexEntityData(pokemon, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LivingEntity resolveEntityScan() {
|
||||
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")
|
||||
)
|
||||
public boolean delegateDismountToController(Player instance, Operation<Boolean> original) {
|
||||
if (this.getVehicle() instanceof PokemonEntity pokemonEntity) {
|
||||
return pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.dismountOnShift(settings, state, pokemonEntity) && original.call(instance);
|
||||
});
|
||||
}
|
||||
return original.call(instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrientationController getOrientationController() {
|
||||
return cobblemon$orientationController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDriverInput(Vector3f driverInput) {
|
||||
cobblemon$driverInput = driverInput;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3f getDriverInput() {
|
||||
return cobblemon$driverInput;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastSentDriverInput(Vector3f lastSentDriverInput) {
|
||||
cobblemon$lastSentDriverInput = lastSentDriverInput;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3f getLastSentDriverInput() {
|
||||
return cobblemon$lastSentDriverInput;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float cobblemon$getRideXRot() {
|
||||
return this.cobblemon$rideXRot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setRideXRot(float rideXRot) {
|
||||
this.cobblemon$rideXRot = rideXRot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float cobblemon$getRideYRot() {
|
||||
return this.cobblemon$rideYRot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setRideYRot(float rideYRot) {
|
||||
this.cobblemon$rideYRot = rideYRot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3 cobblemon$getRideEyePos() {
|
||||
return this.cobblemon$rideEyePos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setRideEyePos(Vec3 rideEyePos) {
|
||||
this.cobblemon$rideEyePos = rideEyePos;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.client.CobblemonClient;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(PlayerRenderer.class)
|
||||
public class PlayerRendererMixin {
|
||||
@Inject(
|
||||
method = "render(Lnet/minecraft/client/player/AbstractClientPlayer;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V",
|
||||
at = @At(value = "TAIL")
|
||||
)
|
||||
public void renderPlayer(AbstractClientPlayer player, float f, float g, PoseStack poseStack, MultiBufferSource multiBufferSource, int i, CallbackInfo ci) {
|
||||
CobblemonClient.INSTANCE.getRequests().onRenderPlayer(player, g);
|
||||
}
|
||||
}
|
||||
@@ -21,9 +21,9 @@ import org.spongepowered.asm.mixin.injection.Slice;
|
||||
public abstract class PointedDripstoneBlockMixin {
|
||||
|
||||
@Redirect(
|
||||
method = "canGrow(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;)Z",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;is(Lnet/minecraft/world/level/block/Block;)Z", ordinal = 0),
|
||||
slice = @Slice(from = @At(value = "FIELD", target = "Lnet/minecraft/world/level/block/Blocks;DRIPSTONE_BLOCK:Lnet/minecraft/world/level/block/Block;"))
|
||||
method = "canTipGrow(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/core/BlockPos;)Z",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;is(Lnet/minecraft/world/level/Block;)Z", ordinal = 0),
|
||||
slice = @Slice(from = @At(value = "FIELD", target = "Lnet/minecraft/world/level/block/Blocks;DRIPSTONE_BLOCK:Lnet/minecraft/world/level/Block;"))
|
||||
)
|
||||
private static boolean cobblemon$validateMoonStoneDripstone(BlockState instance, Block block) {
|
||||
return instance.is(CobblemonBlockTags.DRIPSTONE_GROWABLE);
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue;
|
||||
import com.cobblemon.mod.common.entity.MoLangScriptingEntity;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.block.PowderSnowBlock;
|
||||
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(PowderSnowBlock.class)
|
||||
public abstract class PowderSnowBlockMixin {
|
||||
@Inject(method = "canEntityWalkOnPowderSnow", at = @At(value = "RETURN"), cancellable = true)
|
||||
private static void cobblemon$canEntityWalkOnPowderSnow(Entity entity, CallbackInfoReturnable<Boolean> ci) {
|
||||
if (ci.getReturnValue() == false && entity instanceof MoLangScriptingEntity) {
|
||||
ci.setReturnValue(((MoLangScriptingEntity) entity).getConfig().getMap().getOrDefault("can_stand_on_powder_snow", DoubleValue.ZERO).asDouble() == 1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 net.minecraft.stats.RecipeBookSettings;
|
||||
import net.minecraft.world.inventory.RecipeBookType;
|
||||
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.Map;
|
||||
|
||||
@Mixin(RecipeBookSettings.class)
|
||||
public class RecipeBookSettingsMixin {
|
||||
|
||||
|
||||
@Shadow @Final public Map<RecipeBookType, RecipeBookSettings.TypeSettings> states;
|
||||
|
||||
@Inject(method = "<init>", at = @At("TAIL"))
|
||||
private void cobblemon$init(CallbackInfo ci) {
|
||||
states.put(RecipeBookType.valueOf("COOKING_POT"), new RecipeBookSettings.TypeSettings(true, true));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
import net.minecraft.world.inventory.RecipeBookType;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
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.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(value = RecipeBookType.class)
|
||||
public class RecipeBookTypeMixin {
|
||||
|
||||
@Final
|
||||
@Mutable
|
||||
@Shadow
|
||||
private static RecipeBookType[] $VALUES; // moj
|
||||
|
||||
@Invoker("<init>")
|
||||
private static RecipeBookType cobblemon$createBookType(String name, int ordinal) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "<clinit>",
|
||||
at = @At("TAIL")
|
||||
)
|
||||
private static void cobblemon$addRecipeBookType(CallbackInfo ci) {
|
||||
ArrayList<RecipeBookType> types = new ArrayList<>(List.of($VALUES));
|
||||
types.add(cobblemon$createBookType("COOKING_POT", $VALUES.length));
|
||||
$VALUES = types.toArray(RecipeBookType[]::new);
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.duck.PlayerDuck;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.mixin.accessor.ChunkMapAccessor;
|
||||
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 it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
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 org.joml.Matrix3f;
|
||||
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;
|
||||
|
||||
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;
|
||||
@Unique
|
||||
private Matrix3f cobblemon$lastSentOrientation;
|
||||
@Unique
|
||||
private boolean cobblemon$lastSentActive;
|
||||
|
||||
@Inject(method = "sendChanges", at = @At("TAIL"))
|
||||
private void cobblemon$sendChanges(CallbackInfo ci) {
|
||||
cobblemon$sendOrientationChanges();
|
||||
cobblemon$sendRidingStateChanges();
|
||||
cobblemon$sendDriverInput();
|
||||
}
|
||||
|
||||
private void cobblemon$sendRidingStateChanges() {
|
||||
if (!(this.entity instanceof PokemonEntity pokemonEntity)) return;
|
||||
if (pokemonEntity.getRidingController() == null) return;
|
||||
var ridingController = pokemonEntity.getRidingController();
|
||||
if (ridingController.getContext() == null) return;
|
||||
var context = ridingController.getContext();
|
||||
var ridingBehaviour = context.getBehaviour();
|
||||
var ridingState = context.getState();
|
||||
var previousRidingState = pokemonEntity.getPreviousRidingState();
|
||||
if (previousRidingState != null && !ridingState.shouldSync(previousRidingState)) return;
|
||||
cobblemon$broadcast(new ClientboundUpdateRidingStatePacket(pokemonEntity.getId(), ridingBehaviour, ridingState, null));
|
||||
}
|
||||
|
||||
private void cobblemon$sendOrientationChanges() {
|
||||
if (!(this.entity instanceof OrientationControllable controllable)) return;
|
||||
OrientationController controller = controllable.getOrientationController();
|
||||
Matrix3f currOrientation = controller.getOrientation();
|
||||
boolean currActive = controller.getActive();
|
||||
|
||||
if (currOrientation == null || currOrientation.equals(cobblemon$lastSentOrientation) && (currActive == cobblemon$lastSentActive))
|
||||
return;
|
||||
cobblemon$lastSentOrientation = new Matrix3f(currOrientation);
|
||||
cobblemon$lastSentActive = currActive;
|
||||
|
||||
cobblemon$broadcast(new ClientboundUpdateOrientationPacket(currOrientation, currActive, entity.getId()));
|
||||
}
|
||||
|
||||
private void cobblemon$sendDriverInput() {
|
||||
if (!(this.entity instanceof ServerPlayer serverPlayer)) return;
|
||||
if(!(serverPlayer.getVehicle() instanceof PokemonEntity)) return;
|
||||
Vector3f driverInput = ((PlayerDuck)serverPlayer).getDriverInput();
|
||||
if(driverInput == null) return;
|
||||
|
||||
// If no change in input is detected then don't send a new packet
|
||||
Vector3f lastSentDriverInput = ((PlayerDuck)serverPlayer).getLastSentDriverInput();
|
||||
if (driverInput.equals(lastSentDriverInput)) return;
|
||||
((PlayerDuck)serverPlayer).setLastSentDriverInput(driverInput);
|
||||
cobblemon$broadcast(new ClientboundUpdateDriverInputPacket(driverInput, entity.getId()));
|
||||
}
|
||||
|
||||
private void cobblemon$broadcast(NetworkPacket<?> packet) {
|
||||
if (!(entity.level() instanceof ServerLevel level)) return;
|
||||
ChunkMap chunkMap = level.getChunkSource().chunkMap;
|
||||
Int2ObjectMap<?> entityMap = ((ChunkMapAccessor) chunkMap).getEntityMap();
|
||||
Object tracked = entityMap.get(entity.getId());
|
||||
if (!(tracked instanceof TrackedEntityAccessor tracker)) return;
|
||||
|
||||
Set<ServerPlayerConnection> seenBy = tracker.getSeenBy();
|
||||
for (ServerPlayerConnection conn : seenBy) {
|
||||
ServerPlayer player = conn.getPlayer();
|
||||
if (player == entity) continue;
|
||||
CobblemonNetwork.INSTANCE.sendPacketToPlayer(player, packet);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,44 +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.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
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;
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
@Mixin(ServerLevel.class)
|
||||
public abstract class ServerLevelMixin {
|
||||
|
||||
@Inject(method = "findLightningRod", at = @At(value = "RETURN"), cancellable = true)
|
||||
private void cobblemon$findLightningRod(BlockPos blockPos, CallbackInfoReturnable<Optional<BlockPos>> ci) {
|
||||
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);
|
||||
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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,92 +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.OrientationControllable;
|
||||
import com.cobblemon.mod.common.PlayerSpawnerAccessor;
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner;
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
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.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();
|
||||
|
||||
@Unique
|
||||
public PlayerSpawner cobblemon$spawner;
|
||||
|
||||
@Override
|
||||
public PlayerSpawner getPlayerSpawner() {
|
||||
ServerPlayer player = (ServerPlayer)(Object)this;
|
||||
if (cobblemon$spawner == null) {
|
||||
cobblemon$spawner = PlayerSpawnerFactory.INSTANCE.create(player);
|
||||
}
|
||||
return cobblemon$spawner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerSpawner(PlayerSpawner spawner) {
|
||||
this.cobblemon$spawner = spawner;
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("TAIL"))
|
||||
private void cobblemon$tickSpawner(CallbackInfo ci) {
|
||||
if (!Cobblemon.config.getEnableSpawning()) {
|
||||
return;
|
||||
} else if (!serverLevel().getGameRules().getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING)) {
|
||||
return;
|
||||
}
|
||||
getPlayerSpawner().tick();
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseCustomOrientation(Entity entity) {
|
||||
if (entity == null) return false;
|
||||
if (!(entity instanceof PokemonEntity pokemonEntity)) return false;
|
||||
return pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.shouldRoll(settings, state, pokemonEntity);
|
||||
});
|
||||
}
|
||||
|
||||
@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) {
|
||||
return original && !(entity instanceof PokemonEntity);
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.block.HeartyGrainsBlock;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.WorldGenLevel;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.DoublePlantBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf;
|
||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||
import net.minecraft.world.level.levelgen.feature.SimpleBlockFeature;
|
||||
import net.minecraft.world.level.levelgen.feature.configurations.SimpleBlockConfiguration;
|
||||
import org.spongepowered.asm.mixin.Debug;
|
||||
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(SimpleBlockFeature.class)
|
||||
@Debug(export = true, print = true)
|
||||
public class SimpleBlockFeatureMixin {
|
||||
//this mixin inserts the logic needed to ensure that when hearty grains are of a certain age, they place with the upper block too
|
||||
//similarly to what the doubleblock logic is here
|
||||
@Inject(method = "place", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;canSurvive(Lnet/minecraft/world/level/LevelReader;Lnet/minecraft/core/BlockPos;)Z", shift = At.Shift.AFTER), cancellable = true)
|
||||
public void place(FeaturePlaceContext<SimpleBlockConfiguration> context, CallbackInfoReturnable<Boolean> cir,
|
||||
@Local BlockState blockState, @Local BlockPos blockPos, @Local WorldGenLevel worldGenLevel) {
|
||||
if (!(blockState.getBlock() instanceof HeartyGrainsBlock)) {
|
||||
return;
|
||||
}
|
||||
if (blockState.getValue(HeartyGrainsBlock.Companion.getAGE()) <= HeartyGrainsBlock.AGE_AFTER_HARVEST) {
|
||||
return; //block is too young to be double
|
||||
}
|
||||
if (!worldGenLevel.isEmptyBlock(blockPos.above())) {
|
||||
cir.setReturnValue(false); //no space for the 2nd block above
|
||||
return;
|
||||
}
|
||||
DoublePlantBlock.placeAt(worldGenLevel, blockState, blockPos, Block.UPDATE_CLIENTS);
|
||||
cir.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
@@ -8,33 +8,23 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.api.riding.sound.RideAttenuationModel;
|
||||
import com.cobblemon.mod.common.api.riding.sound.RideLoopSound;
|
||||
import com.cobblemon.mod.common.client.sound.BattleMusicController;
|
||||
import com.cobblemon.mod.common.duck.ChannelDuck;
|
||||
import com.cobblemon.mod.common.duck.SoundEngineDuck;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import com.mojang.blaze3d.audio.Channel;
|
||||
import net.minecraft.client.resources.sounds.Sound;
|
||||
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.sounds.SoundSource;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
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.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(SoundEngine.class)
|
||||
@@ -55,86 +45,6 @@ public abstract class SoundEngineMixin implements SoundEngineDuck {
|
||||
@Shadow
|
||||
public abstract boolean isActive(SoundInstance sound);
|
||||
|
||||
@Inject(method = "play",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/sounds/ChannelAccess$ChannelHandle;execute(Ljava/util/function/Consumer;)V"
|
||||
),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$overrideChannelExecute(
|
||||
SoundInstance sound,
|
||||
CallbackInfo ci,
|
||||
@Local(name = "h") float h,
|
||||
@Local(name = "i") float i,
|
||||
@Local(name = "g") float g,
|
||||
@Local(name = "bl2") boolean bl2,
|
||||
@Local(name = "bl3") boolean bl3,
|
||||
@Local(name = "bl") boolean bl,
|
||||
@Local(name = "vec3") Vec3 vec3,
|
||||
@Local(name = "channelHandle") ChannelAccess.ChannelHandle handle
|
||||
) {
|
||||
if (!(sound instanceof RideLoopSound rideSound)) return;
|
||||
|
||||
if (handle == null) return;
|
||||
|
||||
handle.execute((channel) -> {
|
||||
channel.setPitch(i);
|
||||
channel.setVolume(h);
|
||||
|
||||
if (rideSound.getRideAttenuation() == RideAttenuationModel.LINEAR) {
|
||||
channel.linearAttenuation(g);
|
||||
} else if (rideSound.getRideAttenuation() == RideAttenuationModel.EXPONENTIAL){
|
||||
((ChannelDuck) channel).cobblemon$inverseAttenuation(g);
|
||||
} else {
|
||||
channel.disableAttenuation();
|
||||
}
|
||||
|
||||
// Apply low pass filter if the rideSound dictate that it should be muffled
|
||||
if (rideSound.getShouldMuffle()) {
|
||||
((ChannelDuck) channel).cobblemon$applyLowPassFilter(1.0f, rideSound.getMuffleAmount());
|
||||
} else {
|
||||
((ChannelDuck) channel).cobblemon$clearFilters();
|
||||
}
|
||||
|
||||
channel.setLooping(bl2 && !bl3);
|
||||
channel.setSelfPosition(vec3);
|
||||
channel.setRelative(bl);
|
||||
});
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "tickNonPaused",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/sounds/ChannelAccess$ChannelHandle;execute(Ljava/util/function/Consumer;)V",
|
||||
ordinal = 0
|
||||
)
|
||||
)
|
||||
private void cobblemon$tickableSoundTick(
|
||||
CallbackInfo ci,
|
||||
@Local(name = "tickableSoundInstance") TickableSoundInstance instance,
|
||||
@Local(name = "channelHandle", ordinal = 0) ChannelAccess.ChannelHandle handle,
|
||||
@Local(name = "f", ordinal = 0) float volume,
|
||||
@Local(name = "g", ordinal = 0) float pitch,
|
||||
@Local(name = "vec3", ordinal = 0) Vec3 vec3
|
||||
) {
|
||||
if (!(instance instanceof RideLoopSound rideSound)) return;
|
||||
|
||||
handle.execute(channel -> {
|
||||
channel.setVolume(volume);
|
||||
channel.setPitch(pitch);
|
||||
channel.setSelfPosition(vec3);
|
||||
|
||||
// Apply low pass filter if the rideSound dictate that it should be muffled
|
||||
if (rideSound.getShouldMuffle()) {
|
||||
((ChannelDuck) channel).cobblemon$applyLowPassFilter(1.0f, rideSound.getMuffleAmount());
|
||||
} else {
|
||||
((ChannelDuck) channel).cobblemon$clearFilters();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Resumes the Source belonging to the queried SoundInstance. */
|
||||
private void resume(SoundInstance sound) {
|
||||
ChannelAccess.ChannelHandle sourceManager = this.instanceToChannel.get(sound);
|
||||
|
||||
@@ -8,10 +8,12 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.client.sound.BlockEntitySoundTracker;
|
||||
import com.cobblemon.mod.common.client.sound.EntitySoundTracker;
|
||||
import com.cobblemon.mod.common.client.sound.BattleMusicController;
|
||||
import com.cobblemon.mod.common.client.sound.SoundTracker;
|
||||
import com.cobblemon.mod.common.duck.SoundEngineDuck;
|
||||
import com.cobblemon.mod.common.duck.SoundManagerDuck;
|
||||
import com.cobblemon.mod.common.duck.SoundEngineDuck;
|
||||
import net.minecraft.client.resources.sounds.BiomeAmbientSoundsHandler;
|
||||
import net.minecraft.client.resources.sounds.SoundInstance;
|
||||
import net.minecraft.client.resources.sounds.UnderwaterAmbientSoundInstances;
|
||||
|
||||
@@ -1,67 +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.world.CobblemonStructureIDs;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.LevelHeightAccessor;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.biome.BiomeSource;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.level.levelgen.RandomState;
|
||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||
import net.minecraft.world.level.levelgen.structure.StructurePiece;
|
||||
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@Mixin(Structure.class)
|
||||
public abstract class StructureMixin {
|
||||
// Define a set of structures that should not spawn below Sea Level
|
||||
@Unique
|
||||
private static final Set<ResourceLocation> RESTRICTED_STRUCTURES = new HashSet<>(Arrays.asList(
|
||||
CobblemonStructureIDs.STONJOURNER_HENGE,
|
||||
CobblemonStructureIDs.LUNA_HENGE,
|
||||
CobblemonStructureIDs.SOL_HENGE
|
||||
));
|
||||
|
||||
@Inject(method = "generate", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/levelgen/structure/StructureStart;isValid()Z"),
|
||||
cancellable = true)
|
||||
public void cobblemon$isValid(RegistryAccess registryAccess, ChunkGenerator chunkGenerator, BiomeSource biomeSource,
|
||||
RandomState randomState, StructureTemplateManager structureTemplateManager, long seed,
|
||||
ChunkPos chunkPos, int references, LevelHeightAccessor heightAccessor,
|
||||
Predicate<Holder<Biome>> validBiome,
|
||||
CallbackInfoReturnable<StructureStart> cir,
|
||||
@Local StructureStart structureStart) {
|
||||
ResourceLocation structureKey = registryAccess.registryOrThrow(Registries.STRUCTURE).getKey((Structure) (Object) this);
|
||||
if(!RESTRICTED_STRUCTURES.contains(structureKey)) {
|
||||
return;
|
||||
}
|
||||
for (StructurePiece piece : structureStart.getPieces()) {
|
||||
if (piece.getBoundingBox().minY() < chunkGenerator.getSeaLevel()) {
|
||||
cir.setReturnValue(StructureStart.INVALID_START);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.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.level.Level;
|
||||
import net.minecraft.world.level.block.SweetBerryBushBlock;
|
||||
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.CallbackInfo;
|
||||
|
||||
|
||||
@Mixin(SweetBerryBushBlock.class)
|
||||
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) {
|
||||
if (entity instanceof MoLangScriptingEntity) {
|
||||
if (((MoLangScriptingEntity) entity).getConfig().getMap().getOrDefault("immune_to_sweet_berry_bush_block", DoubleValue.ZERO).asDouble() == 1.0) {
|
||||
callbackInfo.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,9 +25,9 @@ public class TargetingConditionsMixin {
|
||||
@Inject(method = "test", at = @At("HEAD"), cancellable = true)
|
||||
public void test(@Nullable LivingEntity baseEntity, LivingEntity targetEntity, CallbackInfoReturnable<Boolean> ci) {
|
||||
if (targetEntity instanceof ServerPlayer player) {
|
||||
if (player.level().getGameRules().getBoolean(CobblemonGameRules.MOB_TARGET_IN_BATTLE)) return;
|
||||
boolean canTargetInBattle = player.level().getGameRules().getBoolean(CobblemonGameRules.MOB_TARGET_IN_BATTLE);
|
||||
boolean targetInBattle = Cobblemon.INSTANCE.getBattleRegistry().getBattleByParticipatingPlayer(player) != null;
|
||||
if (targetInBattle) ci.setReturnValue(false);
|
||||
if (!canTargetInBattle && targetInBattle) ci.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.world.level.block.entity.BeehiveBlockEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(targets = "net.minecraft.world.level.block.entity.BeehiveBlockEntity$BeeData")
|
||||
public interface BeeDataAccessor {
|
||||
@Invoker("toOccupant")
|
||||
BeehiveBlockEntity.Occupant invokeToOccupant();
|
||||
}
|
||||
|
||||
-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.accessor;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(BeehiveBlockEntity.class)
|
||||
public interface BeehiveBlockEntityAccessor {
|
||||
@Accessor("stored")
|
||||
List<Object> getStored();
|
||||
@Accessor("savedFlowerPos")
|
||||
BlockPos savedFlowerPos();
|
||||
|
||||
|
||||
/**
|
||||
* Access the private static method:
|
||||
* private static void releaseOccupant(Level level, BlockPos pos, BeeData beeData, ...)
|
||||
*/
|
||||
@Invoker("releaseOccupant")
|
||||
static boolean releaseOccupant(Level level, BlockPos pos, BlockState state, BeehiveBlockEntity.Occupant occupant, @Nullable List<Entity> storedInHives, BeehiveBlockEntity.BeeReleaseStatus releaseStatus, @Nullable BlockPos storedFlowerPos) {
|
||||
throw new AssertionError(); // Mixin will overwrite
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,20 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(Camera.class)
|
||||
public interface CameraAccessor {
|
||||
@Accessor("level")
|
||||
BlockGetter getLevel();
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(ChunkMap.class)
|
||||
public interface ChunkMapAccessor {
|
||||
@Accessor("entityMap")
|
||||
Int2ObjectMap<?> getEntityMap();
|
||||
}
|
||||
-22
@@ -1,22 +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.StateSwitchingButton;
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(RecipeBookComponent.class)
|
||||
public interface RecipeBookComponentAccessor {
|
||||
@Accessor("filterButton")
|
||||
StateSwitchingButton getFilterButton();
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.server.level.ServerEntity;
|
||||
import net.minecraft.server.network.ServerPlayerConnection;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@Mixin(targets = "net.minecraft.server.level.ChunkMap$TrackedEntity")
|
||||
public interface TrackedEntityAccessor {
|
||||
@Accessor("seenBy")
|
||||
Set<ServerPlayerConnection> getSeenBy();
|
||||
|
||||
@Accessor("serverEntity")
|
||||
ServerEntity getServerEntity();
|
||||
}
|
||||
-131
@@ -1,131 +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.brewing;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonRecipeTypes;
|
||||
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandInput;
|
||||
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.world.Containers;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.alchemy.PotionBrewing;
|
||||
import net.minecraft.world.item.crafting.RecipeHolder;
|
||||
import net.minecraft.world.item.crafting.RecipeManager;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.LevelEvent;
|
||||
import net.minecraft.world.level.block.entity.BrewingStandBlockEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@Mixin(BrewingStandBlockEntity.class)
|
||||
public class BrewingStandBlockEntityMixin {
|
||||
|
||||
@WrapOperation(method = "serverTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/BrewingStandBlockEntity;doBrew(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/core/NonNullList;)V"))
|
||||
private static void cobblemon$doBrew(Level level, BlockPos pos, NonNullList<ItemStack> slots, Operation<Void> original) {
|
||||
var recipe = cobblemon$fetchBrewingRecipe(slots, level);
|
||||
if(recipe == null) {
|
||||
original.call(level, pos, slots);
|
||||
return;
|
||||
}
|
||||
//copied from vanilla doBrew logic, but slightly tweaked to work for cobblemon, this was needed as replacing the loop was not quite possible inside doBrew
|
||||
ItemStack itemStack = slots.get(3);
|
||||
for(int i = 0; i < 3; ++i) {
|
||||
if (!slots.get(i).isEmpty()){
|
||||
slots.set(i, recipe.getResult().copy());
|
||||
}
|
||||
}
|
||||
|
||||
itemStack.shrink(1);
|
||||
if (itemStack.getItem().hasCraftingRemainingItem()) {
|
||||
ItemStack itemStack2 = new ItemStack(itemStack.getItem().getCraftingRemainingItem());
|
||||
if (itemStack.isEmpty()) {
|
||||
itemStack = itemStack2;
|
||||
} else {
|
||||
Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), itemStack2);
|
||||
}
|
||||
}
|
||||
|
||||
slots.set(3, itemStack);
|
||||
level.levelEvent(LevelEvent.SOUND_BREWING_STAND_BREW, pos, 0);
|
||||
}
|
||||
|
||||
@WrapOperation(method = "serverTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/BrewingStandBlockEntity;isBrewable(Lnet/minecraft/world/item/alchemy/PotionBrewing;Lnet/minecraft/core/NonNullList;)Z"))
|
||||
private static boolean cobblemon$isBrewable(PotionBrewing potionBrewing, NonNullList<ItemStack> items, Operation<Boolean> original,
|
||||
@Local(argsOnly = true) Level level) {
|
||||
return cobblemon$fetchBrewingRecipe(items, level) != null || original.call(potionBrewing, items);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static BrewingStandRecipe cobblemon$fetchBrewingRecipe(NonNullList<ItemStack> items, Level level) {
|
||||
ItemStack ingredient = items.get(3);
|
||||
List<ItemStack> bottles = items.subList(0, 3);
|
||||
|
||||
boolean allBottlesEmpty = true;
|
||||
for (ItemStack bottle : bottles) {
|
||||
if (!bottle.isEmpty()) {
|
||||
allBottlesEmpty = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ingredient.isEmpty() || allBottlesEmpty) {
|
||||
return null;
|
||||
}
|
||||
|
||||
BrewingStandInput input = new BrewingStandInput(ingredient, bottles);
|
||||
RecipeManager recipeManager = level.getRecipeManager();
|
||||
|
||||
Optional<RecipeHolder<BrewingStandRecipe>> recipeHolder =
|
||||
recipeManager.getRecipeFor(CobblemonRecipeTypes.INSTANCE.getBREWING_STAND(), input, level);
|
||||
|
||||
return recipeHolder.map(RecipeHolder::value).orElse(null);
|
||||
}
|
||||
|
||||
@Inject(method = "canPlaceItem", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$canPlaceItem(int slot, ItemStack stack, CallbackInfoReturnable<Boolean> cir) {
|
||||
if (stack == null || stack.isEmpty()) return;
|
||||
|
||||
BrewingStandBlockEntity self = (BrewingStandBlockEntity) (Object) this;
|
||||
Level level = self.getLevel();
|
||||
|
||||
if (level != null) {
|
||||
|
||||
var rm = level.getRecipeManager();
|
||||
|
||||
//Input slot
|
||||
if (slot == 3) {
|
||||
if (BrewingStandRecipe.Companion.isInput(stack, rm)) {
|
||||
cir.setReturnValue(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Output slots
|
||||
if (slot >= 0 && slot < 3) {
|
||||
if (BrewingStandRecipe.Companion.isBottle(stack, rm)) {
|
||||
if (self.getItem(slot).isEmpty()) {
|
||||
cir.setReturnValue(true);
|
||||
} else {
|
||||
cir.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-45
@@ -1,45 +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.brewing;
|
||||
|
||||
import com.cobblemon.mod.common.duck.RecipeAwareSlot;
|
||||
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.BrewingStandMenu;
|
||||
import net.minecraft.world.inventory.ContainerData;
|
||||
import net.minecraft.world.inventory.Slot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(BrewingStandMenu.class)
|
||||
public abstract class BrewingStandMenuMixin {
|
||||
|
||||
@Inject(method = "<init>(ILnet/minecraft/world/entity/player/Inventory;Lnet/minecraft/world/Container;Lnet/minecraft/world/inventory/ContainerData;)V", at = @At("TAIL"))
|
||||
private void captureLevel(int containerId, Inventory playerInventory, Container brewingStandContainer, ContainerData brewingStandData, CallbackInfo ci) {
|
||||
var recipeManager = playerInventory.player.level().getRecipeManager();
|
||||
for (Slot slot : ((BrewingStandMenu) (Object) this).slots) {
|
||||
if (slot instanceof RecipeAwareSlot awareSlot) {
|
||||
awareSlot.setRecipeManager(recipeManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@WrapOperation(method = "quickMoveStack", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/inventory/BrewingStandMenu$PotionSlot;mayPlaceItem(Lnet/minecraft/world/item/ItemStack;)Z"))
|
||||
private boolean cobblemon$isPotionBottle(ItemStack stack, Operation<Boolean> original, @Local(argsOnly = true) Player player) {
|
||||
return BrewingStandRecipe.Companion.isBottle(stack, player.level().getRecipeManager()) || original.call(stack);
|
||||
}
|
||||
}
|
||||
@@ -1,44 +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.brewing;
|
||||
|
||||
import com.cobblemon.mod.common.duck.RecipeAwareSlot;
|
||||
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
|
||||
import net.minecraft.world.inventory.BrewingStandMenu;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.crafting.RecipeManager;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(BrewingStandMenu.IngredientsSlot.class)
|
||||
public class IngredientSlotMixin implements RecipeAwareSlot {
|
||||
|
||||
@Unique
|
||||
private RecipeManager cobblemon$recipeManager;
|
||||
|
||||
@Override
|
||||
public void setRecipeManager(RecipeManager recipeManager) {
|
||||
this.cobblemon$recipeManager = recipeManager;
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "mayPlace",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$mayPlace(ItemStack stack, CallbackInfoReturnable<Boolean> cir) {
|
||||
if (BrewingStandRecipe.Companion.isInput(stack, cobblemon$recipeManager)) {
|
||||
cir.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +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.brewing;
|
||||
|
||||
import com.cobblemon.mod.common.duck.RecipeAwareSlot;
|
||||
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
|
||||
import net.minecraft.world.inventory.BrewingStandMenu;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.crafting.RecipeManager;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(BrewingStandMenu.PotionSlot.class)
|
||||
public class PotionSlotMixin implements RecipeAwareSlot {
|
||||
|
||||
@Unique
|
||||
private RecipeManager cobblemon$recipeManager;
|
||||
|
||||
@Override
|
||||
public void setRecipeManager(RecipeManager recipeManager) {
|
||||
this.cobblemon$recipeManager = recipeManager;
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "mayPlace",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$mayPlace(ItemStack stack, CallbackInfoReturnable<Boolean> cir) {
|
||||
if (BrewingStandRecipe.Companion.isBottle(stack, cobblemon$recipeManager)) {
|
||||
cir.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
-12
@@ -9,10 +9,8 @@
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.client.CobblemonClient;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
@@ -31,16 +29,6 @@ public class AbstractClientPlayerMixin {
|
||||
PokedexUsageContext usageContext = CobblemonClient.INSTANCE.getPokedexUsageContext();
|
||||
if (usageContext.getScanningGuiOpen()) {
|
||||
cir.setReturnValue(usageContext.getFovMultiplier());
|
||||
} else {
|
||||
// Only modify fov through riding if the pokedex is not open
|
||||
LocalPlayer player = (LocalPlayer) (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();
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,283 +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.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.riding.Rideable;
|
||||
import com.cobblemon.mod.common.client.MountedPokemonAnimationRenderController;
|
||||
import com.cobblemon.mod.common.client.render.camera.MountedCameraRenderer;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import com.mojang.blaze3d.Blaze3D;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(Camera.class)
|
||||
public abstract class CameraMixin {
|
||||
@Shadow private Entity entity;
|
||||
@Shadow @Final private Quaternionf rotation;
|
||||
@Shadow @Final private Vector3f forwards;
|
||||
@Shadow @Final private Vector3f up;
|
||||
@Shadow @Final private Vector3f left;
|
||||
@Shadow private float xRot;
|
||||
@Shadow private float yRot;
|
||||
|
||||
@Shadow private float eyeHeight;
|
||||
@Shadow private float eyeHeightOld;
|
||||
|
||||
@Shadow protected abstract void setPosition(Vec3 pos);
|
||||
|
||||
@Shadow private float partialTickTime;
|
||||
|
||||
// Used to help in camera rotation rendering when transitioning
|
||||
// from rolled to unrolled.
|
||||
@Unique private float cobblemon$returnTimer = 0;
|
||||
@Unique private float cobblemon$rollAngleStart = 0;
|
||||
|
||||
@Unique private double cobblemon$lastHandledRotationTime = Double.MIN_VALUE;
|
||||
@Unique private double cobblemon$frameTime = 0.0;
|
||||
|
||||
// Used to as the render rotation for the motion sick camera.
|
||||
@Unique @Nullable private Quaternionf cobblemon$smoothRotation = null;
|
||||
|
||||
|
||||
@Inject(method = "setRotation", at = @At("HEAD"), cancellable = true)
|
||||
public void cobblemon$setRotation(float f, float g, CallbackInfo ci) {
|
||||
// Calculate the current frametime
|
||||
double d = Blaze3D.getTime();
|
||||
this.cobblemon$frameTime = (this.cobblemon$lastHandledRotationTime != Double.MIN_VALUE) ? d - this.cobblemon$lastHandledRotationTime : 0.0;
|
||||
this.cobblemon$lastHandledRotationTime = d;
|
||||
|
||||
// Do no camera rotations if the game is paused
|
||||
if(Minecraft.getInstance().isPaused()) return;
|
||||
|
||||
// Don't assume the camera to be attached to an entity. Ponder Scenes from create et.al. for example aren't.
|
||||
if (this.entity == null) return;
|
||||
var vehicle = this.entity.getVehicle();
|
||||
if (!(vehicle instanceof OrientationControllable controllableVehicle)) return;
|
||||
var instance = (Camera)(Object)this;
|
||||
|
||||
// If the current vehicle has no orientation then return and perform
|
||||
// vanilla camera rotations
|
||||
var vehicleController = controllableVehicle.getOrientationController();
|
||||
if (vehicleController.getOrientation() == null) return;
|
||||
|
||||
// If the controller has been deactivated but the orientation isn't null yet
|
||||
// then perform transition from rolled ride/camera to vanilla
|
||||
if (!vehicleController.isActive() && vehicleController.getOrientation() != null) {
|
||||
cobblemon$applyTransitionRotation(vehicleController, ci);
|
||||
} else { // Otherwise perform cobblemon specific camera rotation and set transition helper variables
|
||||
cobblemon$applyRotation();
|
||||
this.cobblemon$returnTimer = 0;
|
||||
this.cobblemon$rollAngleStart = instance.rotation().getEulerAnglesYXZ(new Vector3f()).z();
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@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();
|
||||
Entity vehicle = entity.getVehicle();
|
||||
MountedPokemonAnimationRenderController.INSTANCE.reset();
|
||||
|
||||
if(vehicle instanceof Rideable){
|
||||
Vec3 position = MountedCameraRenderer.INSTANCE.getCameraPosition(
|
||||
instance,
|
||||
entity,
|
||||
vehicle,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
thirdPersonReverse,
|
||||
eyeHeightOld,
|
||||
eyeHeight
|
||||
);
|
||||
|
||||
if(position != null){
|
||||
setPosition(position);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// reset the rotation values if it is now not being ridden.
|
||||
cobblemon$smoothRotation = null;
|
||||
original.call(instance, x, y, z);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void cobblemon$applyRotation(){
|
||||
var driver = this.entity;
|
||||
if (!(driver.getVehicle() instanceof OrientationControllable controllableVehicle) ||
|
||||
controllableVehicle.getOrientationController().getOrientation() == null ||
|
||||
!controllableVehicle.getOrientationController().getActive()
|
||||
) return;
|
||||
|
||||
// Grab the driver and vehicle orientation controllers.
|
||||
var vehicleController = controllableVehicle.getOrientationController();
|
||||
|
||||
var isDriving = driver.getControlledVehicle() != null;
|
||||
|
||||
// Grab the ride orientation
|
||||
var newRotation = new Quaternionf();
|
||||
|
||||
// If the player is driving then use the current orientation since the driver sets it.
|
||||
// If not then use the smoothed render orientation for passengers otherwise the vehicle rotation will be jerky
|
||||
if (isDriving) {
|
||||
newRotation = vehicleController.getOrientation().normal(new Matrix3f()).getNormalizedRotation(new Quaternionf());
|
||||
} else {
|
||||
newRotation = vehicleController.getRenderOrientation(this.partialTickTime);
|
||||
}
|
||||
|
||||
// Unroll the current rotation if no roll is requested and not currently freelooking.
|
||||
if (Cobblemon.config.getDisableRoll()) {
|
||||
// Init the smooth rotation if it has not been set yet.
|
||||
if (cobblemon$smoothRotation == null) {
|
||||
cobblemon$smoothRotation = new Quaternionf().set(this.rotation);
|
||||
}
|
||||
var rideAngs = newRotation.getEulerAnglesYXZ(new Vector3f());
|
||||
var cameraAngs = cobblemon$smoothRotation.getEulerAnglesYXZ(new Vector3f());
|
||||
|
||||
// var vehicle = (PokemonEntity)driver.getVehicle();
|
||||
// var vel = vehicle.getRidingAnimationData().getVelocitySpring().getInterpolated(this.partialTickTime, 0);
|
||||
// // Grab the target yaw as the current rides yaw. If the horizontal velocity is high enough to be used to
|
||||
// // derive a yaw then use it.
|
||||
// var targetYaw = (double) rideAngs.y();
|
||||
// if ( vel.horizontalDistance() > 0.01) {
|
||||
// // lerp the new rotation towards this y rot at a rate proportional to the horizontal movement speed?
|
||||
// targetYaw = Mth.wrapDegrees(Math.toDegrees(Mth.atan2(vel.x(), vel.z())) + 180.0f);
|
||||
// }
|
||||
|
||||
var degDiff = Mth.degreesDifference((float)Math.toDegrees(cameraAngs.y()), (float)Math.toDegrees(rideAngs.y));
|
||||
var pitchDeadzoneDeg = 15.0; // x degrees of deadzone about +-90 degrees of pitch.
|
||||
var pitchDeg = vehicleController.getPitch();
|
||||
// ConsiderPitch to be already 90 if within the deadzone around it.
|
||||
var cutoffPitch = Math.min(1.0,(Mth.abs(pitchDeg) / (90.0f - pitchDeadzoneDeg))) * 90.0f * Math.signum(pitchDeg);
|
||||
var lerpRateMod = Mth.cos((float)Math.toRadians(cutoffPitch));
|
||||
|
||||
// Apply smoothing from the cameras current yaw to the yaw of the velocity vector of the ride.
|
||||
var k = 10.0f; // Some smoothing constant k
|
||||
var smoothingFactor = lerpRateMod * cobblemon$frameTime * k;
|
||||
var newYaw = cameraAngs.y() + (Math.toRadians(degDiff) * smoothingFactor);
|
||||
|
||||
var newPitch = (float)Mth.lerp(cobblemon$frameTime * k, cameraAngs.x(), rideAngs.x());
|
||||
//var newYaw = (float)Mth.lerp(smoothingFactor, cameraAngs.y(), rideAngs.y());
|
||||
var maxRoll = Math.toRadians(15.0f);
|
||||
var newRoll = (float)Mth.lerp(cobblemon$frameTime * k / 2.0, cameraAngs.z(), Math.abs(lerpRateMod) * Math.sin(rideAngs.z()) * maxRoll);
|
||||
|
||||
// Set rotations
|
||||
var smoothedRot = new Quaternionf().rotateYXZ((float)newYaw, newPitch, newRoll);
|
||||
cobblemon$smoothRotation.set(smoothedRot);
|
||||
newRotation.set(smoothedRot);
|
||||
|
||||
}
|
||||
|
||||
var rotationOffset = 0;
|
||||
if (Minecraft.getInstance().options.getCameraType().isMirrored()) {
|
||||
newRotation.rotateY((float)Math.toRadians(180));
|
||||
rotationOffset = 180;
|
||||
}
|
||||
|
||||
// Get the drivers local look angle in relation to the ride and apply it.
|
||||
if (vehicleController.getActive()) {
|
||||
var vehicleMatrix = new Matrix3f().set(newRotation);
|
||||
var driverMatrix = new Matrix3f();// Base the driver
|
||||
var playerRotater = (RidePassenger)driver;
|
||||
newRotation = vehicleMatrix.mul(
|
||||
driverMatrix.rotateYXZ(
|
||||
-Mth.DEG_TO_RAD * (playerRotater.cobblemon$getRideYRot()),
|
||||
-Mth.DEG_TO_RAD * playerRotater.cobblemon$getRideXRot(),
|
||||
0.0f)
|
||||
).normal(new Matrix3f()).getNormalizedRotation(new Quaternionf());
|
||||
}
|
||||
this.rotation.set(newRotation);
|
||||
var eulerAngs = newRotation.getEulerAnglesXYZ(new Vector3f());
|
||||
this.xRot = eulerAngs.x() * Mth.RAD_TO_DEG;
|
||||
this.yRot = eulerAngs.y() * Mth.RAD_TO_DEG;
|
||||
// Set the drivers rotations to match
|
||||
var driverEulerAngs = new Quaternionf(this.rotation).getEulerAnglesYXZ(new Vector3f());
|
||||
driver.setXRot(-driverEulerAngs.x() * Mth.RAD_TO_DEG + rotationOffset);
|
||||
driver.setYRot(180.0f - (driverEulerAngs.y() * Mth.RAD_TO_DEG));
|
||||
|
||||
OrientationController.Companion.getFORWARDS().rotate(this.rotation, this.forwards);
|
||||
OrientationController.Companion.getUP().rotate(this.rotation, this.up);
|
||||
OrientationController.Companion.getLEFT().rotate(this.rotation, this.left);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void cobblemon$applyTransitionRotation(
|
||||
OrientationController vehicleController,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
// If the transition has just started then
|
||||
if (this.cobblemon$returnTimer == 0.0) {
|
||||
MountedCameraRenderer.INSTANCE.resetDriverRotations((Camera)(Object)this, this.entity);
|
||||
}
|
||||
|
||||
if(this.cobblemon$returnTimer < 1) {
|
||||
//Rotation is taken from entity since we no longer handle mouse ourselves
|
||||
//Stops a period of time when you can't input anything.
|
||||
float interpolatedRoll = Mth.lerp(this.cobblemon$returnTimer, this.cobblemon$rollAngleStart, 0.0f);
|
||||
float pitch = (float) Math.toRadians(-this.entity.getXRot());
|
||||
float yaw = (float) Math.toRadians(180 - this.entity.getYRot());
|
||||
|
||||
Quaternionf interRot = new Quaternionf();
|
||||
interRot.rotationYXZ(yaw, pitch, interpolatedRoll);
|
||||
|
||||
this.rotation.set(interRot);
|
||||
var eulerAngs = interRot.getEulerAnglesXYZ(new Vector3f());
|
||||
this.xRot = eulerAngs.x() * Mth.RAD_TO_DEG;
|
||||
this.yRot = eulerAngs.y() * Mth.RAD_TO_DEG;
|
||||
OrientationController.Companion.getFORWARDS().rotate(this.rotation, this.forwards);
|
||||
OrientationController.Companion.getUP().rotate(this.rotation, this.up);
|
||||
OrientationController.Companion.getLEFT().rotate(this.rotation, this.left);
|
||||
|
||||
if(cobblemon$rollAngleStart == 0){
|
||||
this.cobblemon$returnTimer = 1;
|
||||
vehicleController.reset();
|
||||
MountedCameraRenderer.INSTANCE.resetDriverRotations((Camera)(Object)this, this.entity);
|
||||
return;
|
||||
}
|
||||
this.cobblemon$returnTimer += (partialTickTime * (1.0f/20.0f));
|
||||
ci.cancel();
|
||||
} else {
|
||||
this.cobblemon$returnTimer = 1;
|
||||
vehicleController.reset();
|
||||
MountedCameraRenderer.INSTANCE.resetDriverRotations((Camera)(Object)this, this.entity);
|
||||
}
|
||||
}
|
||||
|
||||
@WrapOperation(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;move(FFF)V", ordinal = 0))
|
||||
public void stopMoveIfRolling(Camera instance, float zoom, float dy, float dx, Operation<Void> original) {
|
||||
Entity entity = instance.getEntity();
|
||||
Entity vehicle = entity.getVehicle();
|
||||
|
||||
if (!(vehicle instanceof PokemonEntity) || Cobblemon.config.getThirdPersonViewBobbing()) {
|
||||
original.call(instance, zoom, dy, dx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,85 +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.CookingPotRecipe;
|
||||
import com.cobblemon.mod.common.item.crafting.CookingPotRecipeBase;
|
||||
import com.cobblemon.mod.common.item.crafting.CookingPotShapelessRecipe;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
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();
|
||||
}
|
||||
}
|
||||
+6
-5
@@ -9,21 +9,22 @@
|
||||
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;
|
||||
import org.spongepowered.asm.mixin.injection.Constant;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyConstant;
|
||||
|
||||
@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) {
|
||||
@ModifyConstant(method = "getEntryAtPosition", constant = @Constant(intValue = 4))
|
||||
public int cobblemon$adjustOnlyIfNecessary(int input) {
|
||||
if(ScrollingWidget.class.isInstance(this)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return original;
|
||||
return input;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.api.scheduling.ClientTaskTracker;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.client.DeltaTracker;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.spongepowered.asm.mixin.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.ModifyArg;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@Mixin(GameRenderer.class)
|
||||
public class GameRendererMixin {
|
||||
@Unique
|
||||
long lastTime = -1;
|
||||
|
||||
@Inject(
|
||||
method = "render",
|
||||
at = @At(value = "TAIL")
|
||||
)
|
||||
public void render(DeltaTracker counter, boolean tick, CallbackInfo ci) {
|
||||
Minecraft client = Minecraft.getInstance();
|
||||
long newTime = System.currentTimeMillis();
|
||||
// Don't play scheduled animations when the game is paused
|
||||
if (client.isPaused()) {
|
||||
lastTime = newTime;
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastTime != -1) {
|
||||
ClientTaskTracker.INSTANCE.update((newTime - lastTime) / 1000F);
|
||||
}
|
||||
lastTime = newTime;
|
||||
}
|
||||
|
||||
@ModifyArg(
|
||||
method = "pick(Lnet/minecraft/world/entity/Entity;DDF)Lnet/minecraft/world/phys/HitResult;",
|
||||
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;"
|
||||
),
|
||||
index = 4
|
||||
)
|
||||
private Predicate<Entity> filterPokemonVehicle(Predicate<Entity> original, @Local(ordinal = 0, argsOnly = true) Entity entity) {
|
||||
return (entityX) -> !(entity.getVehicle() == entityX && entityX instanceof PokemonEntity) && original.test(entityX);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.CobblemonClient;
|
||||
import net.minecraft.client.DeltaTracker;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Gui;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
/**
|
||||
* Mixin to give us a hook to render the PartyOverlay below the Chat
|
||||
*
|
||||
* @author Qu
|
||||
* @since 2022-02-22
|
||||
*/
|
||||
@Mixin(Gui.class)
|
||||
public class GuiMixin {
|
||||
//This injects into the actual BooleanSupplier lambda for the "this.layers.add(layeredDraw, () -> !minecraft.options.hideGui)" call
|
||||
// sus af. You have to get the method name by looking at the bytecode of the class. Can do in intellij By clicking View -> Show Bytecode (top left)
|
||||
@Inject(method = "method_55797", at = @At("HEAD"), cancellable = true)
|
||||
private static void cobblemon$dontRenderUiInPokedex(Minecraft minecraft, CallbackInfoReturnable<Boolean> cir) {
|
||||
if (CobblemonClient.INSTANCE.getPokedexUsageContext().getScanningGuiOpen() && minecraft.options.getCameraType().isFirstPerson()) {
|
||||
cir.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,94 +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.OrientationControllable;
|
||||
import com.cobblemon.mod.common.client.render.player.MountedPlayerRenderer;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.client.model.HumanoidModel;
|
||||
import net.minecraft.client.model.geom.ModelPart;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(HumanoidModel.class)
|
||||
public class HumanoidModelMixin {
|
||||
@Shadow @Final
|
||||
public ModelPart head;
|
||||
@Shadow @Final
|
||||
public ModelPart hat;
|
||||
@Shadow @Final
|
||||
public ModelPart rightArm;
|
||||
@Shadow @Final
|
||||
public ModelPart leftArm;
|
||||
@Shadow @Final
|
||||
public ModelPart rightLeg;
|
||||
@Shadow @Final
|
||||
public ModelPart leftLeg;
|
||||
@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
|
||||
) {
|
||||
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);
|
||||
}
|
||||
|
||||
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 (entity instanceof RidePassenger playerRotater) {
|
||||
//this.head.yRot = playerRotater.cobblemon$getRideYRot();
|
||||
this.head.xRot = playerRotater.cobblemon$getRideXRot();
|
||||
headPitch = playerRotater.cobblemon$getRideXRot();
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
-45
@@ -1,45 +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.OrientationControllable;
|
||||
import com.cobblemon.mod.common.item.PokedexItem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.ItemInHandRenderer;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.joml.Quaternionf;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ItemInHandRenderer.class)
|
||||
public class ItemInHandRendererMixin {
|
||||
@Inject(method = "renderArmWithItem", at = @At(value = "HEAD"), cancellable = true)
|
||||
private void cobblemon$renderArmWithItem(AbstractClientPlayer abstractClientPlayer, float f, float g, InteractionHand interactionHand, float h, ItemStack itemStack, float i, PoseStack poseStack, MultiBufferSource multiBufferSource, int j, CallbackInfo ci) {
|
||||
if (abstractClientPlayer.isUsingItem() && abstractClientPlayer.getUseItem().getItem() instanceof PokedexItem) {
|
||||
ci.cancel();
|
||||
}
|
||||
else if (abstractClientPlayer instanceof OrientationControllable controllable && controllable.getOrientationController().isActive()) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(method = "renderHandsWithItems", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;mulPose(Lorg/joml/Quaternionf;)V", ordinal = 1))
|
||||
private void cobblemon$renderHandswithItems(PoseStack instance, Quaternionf quaternion) {
|
||||
if (!(Minecraft.getInstance().player instanceof OrientationControllable controllable && controllable.getOrientationController().isActive())) {
|
||||
instance.mulPose(quaternion);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,103 +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.ModAPI;
|
||||
import com.cobblemon.mod.common.item.PokeBallItem;
|
||||
import com.cobblemon.mod.common.item.PokedexItem;
|
||||
import com.cobblemon.mod.common.item.WearableItem;
|
||||
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;
|
||||
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();
|
||||
}
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
||||
-37
@@ -1,37 +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.entity.MountedLivingEntityRenderer;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.model.EntityModel;
|
||||
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
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(LivingEntityRenderer.class)
|
||||
public class LivingEntityRendererMixin<T extends LivingEntity, M extends EntityModel<T>> {
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,262 +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.CobblemonNetwork;
|
||||
import com.cobblemon.mod.common.DoubleJump;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.riding.Seat;
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate;
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper;
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState;
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel;
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository;
|
||||
import com.cobblemon.mod.common.duck.PlayerDuck;
|
||||
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.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.LocalPlayer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.ClipContext;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Vector3f;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(LocalPlayer.class)
|
||||
public abstract class LocalPlayerMixin extends AbstractClientPlayer implements OrientationControllable, DoubleJump {
|
||||
|
||||
@Unique Matrix3f cobblemon$lastOrientation;
|
||||
|
||||
@Unique float cobblemon$lastRideXRot;
|
||||
@Unique float cobblemon$lastRideYRot;
|
||||
@Unique Vec3 cobblemon$lastRideEyePos;
|
||||
|
||||
@Unique boolean cobblemon$isDoubleJumping = false;
|
||||
|
||||
@Shadow
|
||||
private float jumpRidingScale;
|
||||
|
||||
@Shadow public Input input;
|
||||
|
||||
@Shadow private int autoJumpTime;
|
||||
|
||||
@Unique private int cobblemon$survivalJumpTriggerTime;
|
||||
|
||||
@Unique private boolean cobblemon$isJumping;
|
||||
|
||||
public LocalPlayerMixin(ClientLevel clientLevel, GameProfile gameProfile) {
|
||||
super(clientLevel, gameProfile);
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientPacketListener;send(Lnet/minecraft/network/protocol/Packet;)V"))
|
||||
private void cobblemon$updateRotationMatrixPassenger(CallbackInfo ci) {
|
||||
if (!(this.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
|
||||
var vehicleController = controllableVehicle.getOrientationController();
|
||||
if (!vehicleController.isActive() || vehicleController.getOrientation() == cobblemon$lastOrientation) return;
|
||||
cobblemon$lastOrientation = vehicleController.getOrientation() != null ? new Matrix3f(vehicleController.getOrientation()) : null;
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateOrientationPacket(this.getVehicle().getId(), vehicleController.getOrientation()));
|
||||
}
|
||||
|
||||
@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;
|
||||
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation((LocalPlayer)(Object)this);
|
||||
var vehicleController = controllableVehicle.getOrientationController();
|
||||
|
||||
// If the player has just switched to riding a custom orientation ride then set their
|
||||
// x and y rots local to the vehicle rots(if the controller wasn't active and will now be active)
|
||||
// This ensures that on transition your camera stays in the same spot
|
||||
if (!vehicleController.isActive() && shouldUseCustomOrientation) {
|
||||
// Set local to the vehicle x and yrot so
|
||||
var playerRotater = (RidePassenger)driver;
|
||||
playerRotater.cobblemon$setRideXRot(Mth.wrapDegrees(driver.getXRot() - vehicle.getXRot()));
|
||||
playerRotater.cobblemon$setRideYRot(Mth.wrapDegrees(driver.getYRot() - vehicle.getYRot()));
|
||||
}
|
||||
|
||||
vehicleController.setActive(shouldUseCustomOrientation);
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
private void cobblemon$updateDriverInputRideTick(CallbackInfo ci) {
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
if (!(this.getVehicle() instanceof PokemonEntity pokemonEntity)) return;
|
||||
|
||||
// Gather driver Input
|
||||
float vertInput = this.jumping ? 1.0f : (((Player)this).isShiftKeyDown() ? -1.0f : 0.0f);
|
||||
Vector3f driverInput = new Vector3f(Math.signum(this.xxa), vertInput, Math.signum(this.zza));
|
||||
|
||||
// Check if player input has changed. If it has then update the last sent and send it
|
||||
Vector3f lastSentDriverInput = ((PlayerDuck)this).getLastSentDriverInput();
|
||||
if (driverInput.equals(lastSentDriverInput)) return;
|
||||
((PlayerDuck)this).setLastSentDriverInput(driverInput);
|
||||
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateDriverInputPacket(driverInput));
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
private void cobblemon$updateRiderRotationsRideTick(CallbackInfo ci) {
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
if (!(this.getVehicle() instanceof PokemonEntity pokemonEntity)) return;
|
||||
|
||||
var passenger = (LocalPlayer)(Object)this;
|
||||
var playerRotater = (RidePassenger)passenger;
|
||||
|
||||
// Gather Rider Rotation info
|
||||
var rideXRot = playerRotater.cobblemon$getRideXRot();
|
||||
var rideYRot = playerRotater.cobblemon$getRideYRot();
|
||||
var rideEyePos = playerRotater.cobblemon$getRideEyePos();
|
||||
|
||||
// Check for a change in the values before sending them.
|
||||
if (cobblemon$lastRideXRot != rideXRot ||
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseCustomOrientation(LocalPlayer player) {
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return false;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return false;
|
||||
return pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.shouldRoll(settings, state, pokemonEntity);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopRiding() {
|
||||
super.stopRiding();
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
if (!(this instanceof OrientationControllable controllableVehicle)) return;
|
||||
controllableVehicle.getOrientationController().setActive(false);
|
||||
}
|
||||
|
||||
@Inject(method = "getJumpRidingScale", at = @At("HEAD"), cancellable = true)
|
||||
public void modifyJumpRidingScale(CallbackInfoReturnable<Float> cir) {
|
||||
LocalPlayer player = (LocalPlayer) (Object) this;
|
||||
if (player.isPassenger() && player.getVehicle() instanceof PokemonEntity pokemonEntity) {
|
||||
var rideValue = pokemonEntity.<Float>ifRidingAvailableSupply(null, (behaviour, settings, state) -> {
|
||||
if (behaviour.canJump(settings, state, pokemonEntity, player)) return null;
|
||||
return behaviour.setRideBar(settings, state, pokemonEntity, player);
|
||||
});
|
||||
if (rideValue != null) {
|
||||
cir.setReturnValue(rideValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "aiStep", at = @At("HEAD"))
|
||||
private void cobblemon$aiStep(CallbackInfo ci) {
|
||||
this.cobblemon$isDoubleJumping = false;
|
||||
this.cobblemon$isJumping = this.input.jumping;
|
||||
}
|
||||
|
||||
@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$survivalJumpTriggerTime != 0) {
|
||||
this.cobblemon$isDoubleJumping = true;
|
||||
this.cobblemon$survivalJumpTriggerTime = 0;
|
||||
}
|
||||
else {
|
||||
this.cobblemon$survivalJumpTriggerTime = 12;
|
||||
}
|
||||
}
|
||||
else if (this.cobblemon$survivalJumpTriggerTime > 0) {
|
||||
this.cobblemon$survivalJumpTriggerTime--;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDoubleJumping() {
|
||||
return this.cobblemon$isDoubleJumping;
|
||||
}
|
||||
|
||||
@Inject(method = "isHandsBusy", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$isHandsBusy(CallbackInfoReturnable<Boolean> cir) {
|
||||
Entity vehicle = this.getVehicle();
|
||||
if (vehicle instanceof PokemonEntity pokemonEntity) {
|
||||
int seatIndex = pokemonEntity.getPassengers().indexOf(this);
|
||||
Seat seat = pokemonEntity.getSeats().get(seatIndex);
|
||||
cir.setReturnValue(seat.getHandsBusy());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HitResult pick(double hitDistance, float partialTicks, boolean hitFluids) {
|
||||
Entity vehicle = this.getVehicle();
|
||||
if (vehicle instanceof PokemonEntity pokemonEntity) {
|
||||
|
||||
// Get player object
|
||||
var passenger = (LocalPlayer)(Object)this;
|
||||
var playerRotater = (RidePassenger)passenger;
|
||||
|
||||
// Gather eye position from stored 1st person camera position calculation
|
||||
var eyePosition = playerRotater.cobblemon$getRideEyePos();
|
||||
|
||||
Vec3 viewVector = this.getViewVector(partialTicks);
|
||||
Vec3 viewDistanceVector = eyePosition.add(viewVector.x * hitDistance, viewVector.y * hitDistance, viewVector.z * hitDistance);
|
||||
|
||||
return this.level()
|
||||
.clip(
|
||||
new ClipContext(
|
||||
eyePosition, viewDistanceVector, ClipContext.Block.OUTLINE, hitFluids ? net.minecraft.world.level.ClipContext.Fluid.ANY : net.minecraft.world.level.ClipContext.Fluid.NONE, this
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return super.pick(hitDistance, partialTicks, hitFluids);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static @NotNull Vector3f cobblemon$getFirstPersonOffset(PosableModel model, String locatorName) {
|
||||
Map<String, Vec3> cameraOffsets = model.getFirstPersonCameraOffset();
|
||||
|
||||
if (cameraOffsets.containsKey(locatorName)) {
|
||||
return cameraOffsets.get(locatorName).toVector3f();
|
||||
} else {
|
||||
return new Vector3f(0f, 0f, 0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,329 +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.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.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;
|
||||
import kotlin.Pair;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.MouseHandler;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.SmoothDouble;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
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();
|
||||
@Unique SmoothDouble yMouseSmoother = new SmoothDouble();
|
||||
@Unique SmoothDouble pitchSmoother = new SmoothDouble();
|
||||
@Unique SmoothDouble rollSmoother = new SmoothDouble();
|
||||
@Unique SmoothDouble yawSmoother = new SmoothDouble();
|
||||
|
||||
@Shadow @Final private SmoothDouble smoothTurnY;
|
||||
|
||||
@Shadow @Final private SmoothDouble smoothTurnX;
|
||||
|
||||
@Shadow private double accumulatedDX;
|
||||
|
||||
@Shadow private double accumulatedDY;
|
||||
|
||||
@Shadow private double lastHandleMovementTime;
|
||||
|
||||
@Shadow public abstract boolean isMouseGrabbed();
|
||||
|
||||
@Shadow protected abstract void turnPlayer(double movementTime);
|
||||
|
||||
@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();
|
||||
} else if (i < 0) {
|
||||
accumulatedScrollY -= i;
|
||||
CobblemonClient.INSTANCE.getStorage().shiftSelected(true);
|
||||
ci.cancel();
|
||||
PartySendBinding.INSTANCE.actioned();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/player/LocalPlayer;turn(DD)V"
|
||||
)
|
||||
)
|
||||
public boolean cobblemon$modifyRotation(
|
||||
LocalPlayer player,
|
||||
double cursorDeltaX,
|
||||
double cursorDeltaY,
|
||||
@Local(argsOnly = true) double d,
|
||||
@Local(argsOnly = true) double movementTime
|
||||
) {
|
||||
PokedexUsageContext usageContext = CobblemonClient.INSTANCE.getPokedexUsageContext();
|
||||
if (usageContext.getScanningGuiOpen()) {
|
||||
this.smoothTurnY.reset();
|
||||
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));
|
||||
}
|
||||
|
||||
var vehicle = player.getVehicle();
|
||||
if (!(vehicle instanceof PokemonEntity)) return true;
|
||||
|
||||
// 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();
|
||||
yMouseSmoother.reset();
|
||||
pitchSmoother.reset();
|
||||
rollSmoother.reset();
|
||||
yawSmoother.reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
var vehicleController = controllableVehicle.getOrientationController();
|
||||
var lookaroundButtonPressed = Minecraft.getInstance().mouseHandler.isMiddlePressed();
|
||||
Pair<Boolean, Boolean> mouseShouldModifyDriver = ((PokemonEntity) vehicle).ifRidingAvailableSupply(new Pair(false, false), (behaviour, settings, state) -> {
|
||||
return behaviour.mouseModifiesDriverRotation(
|
||||
settings,
|
||||
state,
|
||||
(PokemonEntity) vehicle
|
||||
);
|
||||
});
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// If looking around then modify the players orientation instead and zero the mouse deltas so the mouse doesn't
|
||||
// affect the vehicle orientation when looking around.
|
||||
// If the client is a passenger it will modify these rotations and return
|
||||
//-------------------------------------------------------------------------
|
||||
if (lookaroundButtonPressed || player.getControlledVehicle() == null) {
|
||||
// Modify driver rotations
|
||||
cobblemon$setDriverRotations(player, cursorDeltaX, cursorDeltaY);
|
||||
|
||||
// If the player/passenger is not the driver then return and ignore all vehicle rotation logic
|
||||
if (player.getControlledVehicle() == null) return false;
|
||||
|
||||
// Set to zero so that vehicle rotations don't also get affected by movement.
|
||||
cursorDeltaX = 0.0;
|
||||
cursorDeltaY = 0.0;
|
||||
} else if (mouseShouldModifyDriver.getFirst()) { // If not freelooking then check modification per mouse input dimension
|
||||
cobblemon$setDriverRotations(player, cursorDeltaX, 0.0);
|
||||
cursorDeltaX = 0.0;
|
||||
} else if (mouseShouldModifyDriver.getSecond()) {
|
||||
cobblemon$setDriverRotations(player, 0.0, cursorDeltaY);
|
||||
cursorDeltaY = 0.0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Smoothly return driver rotations to zero when needed
|
||||
//-------------------------------------------------------------------------
|
||||
var playerRotater = (RidePassenger)player;
|
||||
if( !lookaroundButtonPressed && !mouseShouldModifyDriver.getFirst()){
|
||||
playerRotater.cobblemon$setRideYRot(lerp(min(5.0f * (float)movementTime, 1.0f), Mth.wrapDegrees(playerRotater.cobblemon$getRideYRot()), 0.0f));
|
||||
}
|
||||
if( !lookaroundButtonPressed && !mouseShouldModifyDriver.getSecond()) {
|
||||
playerRotater.cobblemon$setRideXRot(lerp(min(5.0f * (float)movementTime, 1.0f), Mth.wrapDegrees(playerRotater.cobblemon$getRideXRot()), 0.0f));
|
||||
}
|
||||
|
||||
// Send mouse input to be interpreted into rotation deltas by the ride controller
|
||||
Vec3 angVecMouse = cobblemon$getRideMouseRotation(cursorDeltaX, cursorDeltaY, movementTime);
|
||||
|
||||
// Perform Rotation using mouse influenced rotation deltas.
|
||||
vehicleController.rotate(
|
||||
(float) angVecMouse.x,
|
||||
(float) angVecMouse.y,
|
||||
(float) angVecMouse.z
|
||||
);
|
||||
|
||||
// Gather and apply the current rotation deltas
|
||||
var angRot = cobblemon$getAngularVelocity(movementTime);
|
||||
|
||||
// Apply smoothing if requested by the controller.
|
||||
if(cobblemon$shouldUseAngVelSmoothing()) {
|
||||
var yaw = yawSmoother.getNewDeltaValue(angRot.x * 0.5f, d);
|
||||
var pitch = pitchSmoother.getNewDeltaValue(angRot.y * 0.5f, d);
|
||||
var roll = rollSmoother.getNewDeltaValue(angRot.z * 0.5f, d);
|
||||
vehicleController.rotate((float) yaw, (float) pitch, (float) roll);
|
||||
}
|
||||
else {
|
||||
vehicleController.rotate((float) (angRot.x * 10 * d), (float) (angRot.y * 10 * d), (float) (angRot.z * 10 * d));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Inject(method = "handleAccumulatedMovement", at = @At("HEAD"))
|
||||
private void cobblemon$maintainMovementWhenInScreens2(CallbackInfo ci) {
|
||||
double time = Blaze3D.getTime();
|
||||
cobblemon$timeDelta = time - this.lastHandleMovementTime;
|
||||
}
|
||||
|
||||
@Inject(method = "handleAccumulatedMovement", at = @At("TAIL"))
|
||||
private void cobblemon$maintainMovementWhenInScreens(CallbackInfo ci) {
|
||||
if (minecraft.player == null) return;
|
||||
if (!(minecraft.player.getVehicle() instanceof OrientationControllable vehicleControllable)) return;
|
||||
if (!(vehicleControllable.getOrientationController() instanceof OrientationController vehicleController)) return;
|
||||
if (vehicleController.getOrientation() == null) return;
|
||||
if (minecraft.isPaused()) return;
|
||||
if (this.isMouseGrabbed()) return; // return if turnPlayer() has already run this pass
|
||||
|
||||
this.turnPlayer(cobblemon$timeDelta);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private Vec3 cobblemon$getAngularVelocity(double deltaTime) {
|
||||
var player = minecraft.player;
|
||||
if (player == null) return Vec3.ZERO;
|
||||
if (!(player instanceof OrientationControllable)) return Vec3.ZERO;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return Vec3.ZERO;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return Vec3.ZERO;
|
||||
return pokemonEntity.ifRidingAvailableSupply(Vec3.ZERO, (behaviour, settings, state) -> {
|
||||
return behaviour.angRollVel(settings, state, pokemonEntity, player, deltaTime);
|
||||
});
|
||||
}
|
||||
|
||||
@Unique
|
||||
private Vec3 cobblemon$getRideMouseRotation(double mouseX, double mouseY, double deltaTime) {
|
||||
var player = minecraft.player;
|
||||
if (player == null) return Vec3.ZERO;
|
||||
var vehicle = player.getVehicle();
|
||||
if (vehicle == null) return Vec3.ZERO;
|
||||
if (!(vehicle instanceof PokemonEntity pokemonEntity)) return Vec3.ZERO;
|
||||
|
||||
var invertYaw = Cobblemon.config.getInvertYaw();
|
||||
var invertPitch = Cobblemon.config.getInvertPitch();
|
||||
|
||||
var xValue = mouseX * Cobblemon.config.getXAxisSensitivity();
|
||||
var yValue = mouseY * Cobblemon.config.getYAxisSensitivity();
|
||||
|
||||
var swapXAndY = Cobblemon.config.getSwapXAndYAxes();
|
||||
|
||||
var yaw = (swapXAndY ? yValue : xValue) * (invertYaw? -1.0f : 1.0f);
|
||||
|
||||
var pitch = (swapXAndY ? xValue : yValue) * (invertPitch? -1.0f : 1.0f);
|
||||
|
||||
var sensitivity = cobblemon$getRidingSensitivity();
|
||||
return pokemonEntity.ifRidingAvailableSupply(Vec3.ZERO, (behaviour, settings, state) -> {
|
||||
return behaviour.rotationOnMouseXY(
|
||||
settings,
|
||||
state,
|
||||
pokemonEntity,
|
||||
player,
|
||||
pitch,
|
||||
yaw,
|
||||
yMouseSmoother,
|
||||
xMouseSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Unique
|
||||
private double cobblemon$getRidingSensitivity() {
|
||||
var sensitivity = this.minecraft.options.sensitivity().get() * 0.6000000238418579 + 0.20000000298023224;
|
||||
return Math.pow(sensitivity, 3);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void cobblemon$setDriverRotations(LocalPlayer player, double cursorDeltaX, double cursorDeltaY) {
|
||||
// the vanilla turn() method redone so that it uses rideRotations.
|
||||
float f = (float)cursorDeltaY * 0.15F; // Note: turn() uses xRot for pitch (up/down)
|
||||
float g = (float)cursorDeltaX * 0.15F; // Note: turn() uses yRot for yaw (left/right)
|
||||
var playerRotater = (RidePassenger)player;
|
||||
playerRotater.cobblemon$setRideXRot(playerRotater.cobblemon$getRideXRot() + f);
|
||||
playerRotater.cobblemon$setRideYRot(playerRotater.cobblemon$getRideYRot() + g);
|
||||
playerRotater.cobblemon$setRideXRot(Mth.clamp(playerRotater.cobblemon$getRideXRot(), -90.0F, 90.0F));
|
||||
if (player.getVehicle() != null) {
|
||||
player.getVehicle().onPassengerTurned(player);
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseAngVelSmoothing() {
|
||||
var player = minecraft.player;
|
||||
if (player == null) return true;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return true;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return true;
|
||||
return pokemonEntity.ifRidingAvailableSupply(true, (behaviour, settings, state) -> {
|
||||
return behaviour.useAngVelSmoothing(settings, state, pokemonEntity);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +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.OrientationControllable;
|
||||
import net.minecraft.client.CameraType;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.Options;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(Options.class)
|
||||
public abstract class OptionsMixin {
|
||||
|
||||
/**
|
||||
* Only allow third person on rollables when motion sick cam is enabled
|
||||
*/
|
||||
@Inject(
|
||||
method = "getCameraType",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$forceThirdPerson(CallbackInfoReturnable<CameraType> cir) {
|
||||
var mc = Minecraft.getInstance();
|
||||
if(!(mc.player instanceof Player player)) return;
|
||||
if(!(player.getVehicle() instanceof OrientationControllable vehicle)) return;
|
||||
if(vehicle.getOrientationController() == null) return;
|
||||
|
||||
// Force third person if on an active rollable vehicle and roll is disabled.
|
||||
if (Cobblemon.config.getDisableRoll() && vehicle.getOrientationController().isActive()) {
|
||||
cir.setReturnValue(CameraType.THIRD_PERSON_BACK);
|
||||
cir.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user