mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-22 07:06:23 -04:00
Compare commits
17
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba3207d176 | ||
|
|
762f9ce5f1 | ||
|
|
6c12198344 | ||
|
|
99a0ec7f0d | ||
|
|
aacebc9726 | ||
|
|
378c85b7dd | ||
|
|
c4614ff418 | ||
|
|
8cbbd2de27 | ||
|
|
067c59a636 | ||
|
|
98a02438da | ||
|
|
26b25c8c39 | ||
|
|
bfd78c1a85 | ||
|
|
239485ccb5 | ||
|
|
ff959daaef | ||
|
|
32bb340260 | ||
|
|
b7bfc6d0a1 | ||
|
|
d86879095f |
@@ -24,7 +24,6 @@ eclipse
|
||||
run
|
||||
runClient
|
||||
runServer
|
||||
utilityscripts/implementation/*.txt
|
||||
|
||||
# Files from Forge MDK
|
||||
forge*changelog.txt
|
||||
@@ -37,11 +36,9 @@ common/src/main/resources/assets/cobblemon/showdown
|
||||
# Generated files
|
||||
*/generated/resources/*
|
||||
/fabric/src/generated/resources/cobblemon-common.accesswidener
|
||||
/fabric/src/main/generated/*
|
||||
/.ignored/
|
||||
common/.fabric
|
||||
.kotlin/
|
||||
|
||||
# MacOS
|
||||
.DS_Store
|
||||
/common/config/*
|
||||
|
||||
+2
-9
@@ -16,7 +16,6 @@ check_assets_cache:
|
||||
stage: preprocessing
|
||||
script:
|
||||
- echo "Checking if cached hash matches current hash"
|
||||
- yum install -y findutils
|
||||
|
||||
# Calculate the current hash
|
||||
- find common/src/main/resources/assets common/src/main/resources/data -type f -exec sha256sum {} + | sort -k 2 | sha256sum > current_hash.txt
|
||||
@@ -72,8 +71,8 @@ setup_packsquash:
|
||||
- echo "Installing wget & unzip"
|
||||
- yum install -y wget unzip
|
||||
- echo "Downloading PackSquash"
|
||||
- wget https://github.com/ComunidadAylas/PackSquash/releases/download/v0.4.1/packsquash-x86_64-unknown-linux-musl.zip
|
||||
- unzip packsquash-x86_64-unknown-linux-musl.zip -d ./packsquash_bin
|
||||
- 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
|
||||
@@ -149,7 +148,6 @@ build:
|
||||
dependencies:
|
||||
- replace_resources
|
||||
script:
|
||||
- yum install -y findutils
|
||||
- export GRADLE_OPTS="-Xmx4G -Xms4G"
|
||||
- chmod +x ./gradlew
|
||||
- ./gradlew build
|
||||
@@ -157,9 +155,6 @@ build:
|
||||
paths:
|
||||
- neoforge/build/libs
|
||||
- fabric/build/libs
|
||||
exclude:
|
||||
- neoforge/build/libs/*-dev-shadow.jar
|
||||
- fabric/build/libs/*-dev-shadow.jar
|
||||
|
||||
publish:
|
||||
stage: deploy
|
||||
@@ -168,7 +163,6 @@ publish:
|
||||
rules:
|
||||
- if: '$CI_PROJECT_PATH == "cable-mc/cobblemon" && $CI_COMMIT_BRANCH == "main"'
|
||||
script:
|
||||
- yum install -y findutils
|
||||
- export GRADLE_OPTS="-Xmx4G -Xms4G"
|
||||
- chmod +x ./gradlew
|
||||
- ./gradlew publish
|
||||
@@ -182,7 +176,6 @@ deploy_artifacts:
|
||||
dependencies:
|
||||
- build
|
||||
script:
|
||||
- yum install -y findutils
|
||||
- echo "Collecting artifacts..."
|
||||
- find neoforge/build/libs/ -type f -name "*.jar" | grep -vE "dev-shadow|sources|javadoc" | xargs -I {} mv {} ./
|
||||
- find fabric/build/libs/ -type f -name "*.jar" | grep -vE "dev-shadow|sources|javadoc" | xargs -I {} mv {} ./
|
||||
|
||||
Generated
BIN
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
@@ -1,11 +0,0 @@
|
||||
### Additions
|
||||
|
||||
### Changes
|
||||
- Replaced the entity AI for Pokémon and NPCs with an entirely custom one. Yeah we changed the entity AI in 1.7 too, you're remembering right.
|
||||
- Improved performance of entity AI.
|
||||
|
||||
### Fixes
|
||||
|
||||
### Developer
|
||||
|
||||
### Molang & Datapacks
|
||||
@@ -1,8 +0,0 @@
|
||||
|
||||
### Additions
|
||||
- Added Pokémon breeding for Pokémon left in pasture blocks.
|
||||
- Added nest blocks that Pokémon can lay eggs in.
|
||||
|
||||
### 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.
|
||||
+35
-85
@@ -1,101 +1,51 @@
|
||||
# Changelog
|
||||
## [1.8.2 (MONTH xth, 2026)](#1-8-2)
|
||||
## [1.7.2 (MONTH Xth, YEAR)](#1-7-2)
|
||||
|
||||
### Additions
|
||||
- The following items can now be placed on the ground as blocks:
|
||||
- King's Rock, Galarica Cuff, Unremarkable Teacup, Masterpiece Teacup, Chipped Pot, Cracked Pot, Sachet, Metal Powder, Quick Powder, Bright Powder, Icy Rock, Heat Rock, Smooth Rock, Damp Rock, Destiny Knot, Luminous Moss, Never-Melt Ice, Wide Lens, Scope Lens, and Zoom Lens.
|
||||
- Iron Ball, Metal Coat, Throat Spray, HP Up, Protein, Iron, Carbos, Calcium, Zinc, PP Up, PP Max, Upgrade, Dubious Disc, and Loaded Dice.
|
||||
- The following items can now be placed on various surfaces:
|
||||
- Galarica Wreath, Magnet, Flame Orb, Life Orb, Toxic Orb, Light Ball, and Smoke Ball.
|
||||
- The following items can now be placed as blocks and have additional functionality:
|
||||
- Ring Target, Metronome, and Eject Button.
|
||||
- The following items can now be worn by Players and Pokémon:
|
||||
- Galarica Wreath, Cleanse Tag, Spell Tag, Sharp Beak, Covert Cloak, Shell Helmet, and Never-Melt Ice.
|
||||
- Wearable items can now be equipped by a player by holding it and right-clicking (or rebound use/interact)
|
||||
- Wearable items that can be placed down are exempt from this behaviour.
|
||||
|
||||
### Pokémon Added
|
||||
#### Generation 4
|
||||
- Snover
|
||||
- Abomasnow
|
||||
- Burmy
|
||||
- Wormadam
|
||||
- Mothim
|
||||
|
||||
#### Generation 5
|
||||
- Tympole
|
||||
- Palpitoad
|
||||
- Seismitoad
|
||||
|
||||
#### Generation 6
|
||||
- Helioptile
|
||||
- Heliolisk
|
||||
|
||||
#### Generation 7
|
||||
- Grubbin
|
||||
- Charjabug
|
||||
- Vikavolt
|
||||
|
||||
#### Generation 9
|
||||
- Greavard
|
||||
- Houndstone
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
- Cacnea
|
||||
- Cacturne
|
||||
- Binacle
|
||||
- Barbaracle
|
||||
- Glimmet
|
||||
- Glimmora
|
||||
- Deerling
|
||||
- Sawsbuck (All forms)
|
||||
- Absol
|
||||
|
||||
### Animation updates for the following Pokémon
|
||||
- Cacnea
|
||||
- Cacturne
|
||||
- Added riding statistics: `Distance by Pokémon on Land`, `Distance by Pokémon in Air` and `Distance by Pokémon in Liquid`.
|
||||
- Added the Partner Mark, which party Pokémon have a very small chance to earn as the player walks, provided they have enough friendship.
|
||||
- Added trades for Saccharine Saplings, Hearty Grains, Chipped Pot, and Masterpiece Teacup to the Wandering Trader.
|
||||
- Added brewing recipe for Throat Spray.
|
||||
- Added official Controlify Support
|
||||
- Added new effects
|
||||
- Mental Restoration: Reduces "Time Since Last Rest" statistic, which controls Insomnia, by half a minute per second per effect level
|
||||
- Negative Effect Cleanse: Removes all negative effects
|
||||
- Effect Cleanse: Removes all effects
|
||||
- Added more seasonings for sinister tea
|
||||
- Mental Herb - Mental Restoration I for 10 seconds
|
||||
- White Herb - Negative Effect Cleanse
|
||||
- Milk - Effect Cleanse
|
||||
- Moomoo Milk - Effect Cleanse
|
||||
|
||||
### Changes
|
||||
- Updated various recipes to display in Recipe Groups within the Recipe Book
|
||||
- Updated most recipes to display more logically/consistently within the Recipe Book's categories
|
||||
- Make ride rotations less jittery in multiplayer.
|
||||
- Changes tm shelf discs to use textures instead of tinting and overlays to line up with item display
|
||||
- Blank TM can now be inserted into the Disc Shelf
|
||||
- Ride sounds have been separated into stereo for passengers and mono for other players. Riding will now sound more spacious.
|
||||
|
||||
### Fixes
|
||||
- Correctly grants "They're Minerals!" advancement when planting a type gem
|
||||
- Type Gem Blocks now have advancements to give you the recipe in the recipe book (the data for the advancements were inside the recipes somehow??)
|
||||
- Some other recipes without advancements have also been corrected
|
||||
- Corrected the TM Recipes for Charge Beam and Payday
|
||||
- Type Gem blocks now properly generate clusters off of the block.
|
||||
- Starter Screen Categories will no longer stop rendering if they are bigger than the viewport, and you are not viewing top or bottom edges
|
||||
- Random Starter option now properly handled in height calculation, so now it won't run off into other categories or be un-accessible due to scroll limits if it causes a new row
|
||||
- Mochi and Feathers no longer drop glass bottles on use
|
||||
- Fixed a rare set of concurrency bugs related to reloading packs on NeoForge; fixes a ModernFix issue
|
||||
- Removed unnecessary conditions for Mimikyu's standing pose. Hopefully fixes the rare instance of it using its shoulder animations during battle in multiplayer scenarios.
|
||||
- Fixed Rockruff line not blinking
|
||||
- Fixed Flygon sometimes using its running animation instead of walking
|
||||
- Fixed Bramblin always sleeping outside of battle
|
||||
- Fixed Dragonair using its battle idle as a normal idle
|
||||
- Fixed Lycanroc's head movement
|
||||
- Added head movement to Archaludon
|
||||
- Fixed Duraludon line not having any sleep animations
|
||||
- Fixed Diglett line not having their faint animations
|
||||
- Fixed Kingambit moving its legs while walking
|
||||
- Various Structure fixes
|
||||
- Fixed shiny pokemon under certain circumstances forgetting taught TMs
|
||||
- Fixed orientation not getting reset after crashing while flying and getting back on the Pokémon.
|
||||
- Fixed Furfrou not being trimmable on NeoForge.
|
||||
- Fixed shiny Pokémon not respecting the silent flag on spawn.
|
||||
- Fixed honey from Saccharine Leaves being harvestable at less than the max age.
|
||||
- Items given from interacting with Saccharine Leaves are placed in the active hotbar slot if possible.
|
||||
- Fix all Pokémon being saved to chunks and never despawning.
|
||||
- Fixed PokeSnacks crashing if there was no available spawn.
|
||||
- Fixed Pokémon spawn influences not being specific to regional forms
|
||||
- Fixed crashing when viewing another player in spectator mode
|
||||
- Fixed missing apricorn textures for Adorn blocks
|
||||
- Fixed crashing when riding due to malformed json file, instead resetting it
|
||||
- Fixed mochi items consuming two items at a time
|
||||
- Fix item interaction sometimes not working properly when playing on servers.
|
||||
- Fixed Soothe Bell not being properly tagged as a held item.
|
||||
- Fixed Mint Leaves not being usable for filling the Resurrection Machine.
|
||||
- Added Saccharine Boats and Saccharine Boat with Chests to relevant boat tags.
|
||||
|
||||
### Developer
|
||||
- Fixed wrong order of operations in the code flow prior to the `FOSSIL_REVIVED` event causing pokemon to appear without entity link
|
||||
- Fixed TestPartySlot command not correctly comparing the provided spec with the target Pokémon
|
||||
- Changed the `owner` parameter in the `OwnerQueryRequirement` interface from `ServerPlayer` to `Player`. This method is now also called on the client to verify whether a Pokémon interaction succeeded, so make sure to update your implementations to handle both server and client contexts.
|
||||
|
||||
### Molang & Datapacks
|
||||
- A new `negate` variant for evolution requirements has been added, which will negate (invert) the provided inner condition.
|
||||
- Added Molang functions for individual Pokédex ids, wherein a subdex is passed in as a string to `dex_caught_count` etc.
|
||||
- Ride sounds can now be set as exclusive to passengers
|
||||
- Ride sounds no longer play when submerged unless specified with a new setting
|
||||
|
||||
### Particles
|
||||
|
||||
#### New Move Animations
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
@@ -1,223 +0,0 @@
|
||||
# Habitat Block GUI Editor - Developer Instructions
|
||||
These instructions are brought to you by AI slop with Hiroku reviewing it afterwards. It does seem fairly accurate
|
||||
though.
|
||||
|
||||
## Overview
|
||||
The Habitat Block is a spawning tool that allows creative mode players to configure custom Pokémon spawning behavior. We need a GUI editor so read below to understand what it needs to do.
|
||||
|
||||
Phases might need a bit of explanation. The idea is that each habitat block will have a current "phase", which changes every day. The number of different phases is something that can be configured per block, as well as what order the phase will move through when it changes.
|
||||
|
||||
In the case of 3 phases, the different phase orders do the following:
|
||||
SIMPLE: 1-2-3-1-2-3-1-2-3
|
||||
FIXED_RANDOM: 1-3-2-1-3-2-1-3-2 (or some other repeating pattern, based on the position of the habitat block)
|
||||
FULL_RANDOM: 1-3-1-2-3-1-3-1-2 (completely random value each day)
|
||||
|
||||
The idea is like, if you had set 3 phases for a habitat block, you could make Rattata spawn in phase 1, Patrat in phase 2, and Zigzagoon in phase 3.
|
||||
|
||||
## Entry Point
|
||||
- GUI opens when a creative mode player right-clicks a Habitat Block
|
||||
- Packet: `OpenHabitatBlockEditorPacket` sends current settings to client
|
||||
- When you're done you send a `SaveHabitatBlockSettingsPacket` back to the server with the same settings DTO instance (but modified, one would assume)
|
||||
- Settings are applied via `HabitatBlockEntity.applySettings(HabitatSettingsDTO)`
|
||||
|
||||
## Data Structure
|
||||
|
||||
### Root: `HabitatSettingsDTO`
|
||||
All settings are contained in this DTO which is sent between client and server.
|
||||
|
||||
#### Common Settings (always present)
|
||||
```kotlin
|
||||
numberOfPhases: Int = 1 // Number of spawn phases (TODO: not yet implemented)
|
||||
phaseOrder: HabitatPhaseOrder // How the passage of phases will work with each day
|
||||
levelRange: IntRange // Min..Max level for spawned Pokémon
|
||||
modifiers: String // PokemonProperties string (e.g., "shiny gender=male")
|
||||
mimicId: ResourceLocation // Block appearance (e.g., "minecraft:stone")
|
||||
```
|
||||
|
||||
#### Spawning Mode Toggle
|
||||
```kotlin
|
||||
isActivatedSpawning: Boolean // true = Activated mode, false = Natural mode
|
||||
```
|
||||
|
||||
Based on this boolean, EITHER `activatedSettings` OR `naturalSettings` will be populated (never both).
|
||||
|
||||
---
|
||||
|
||||
## Spawning Modes
|
||||
|
||||
### Mode 1: Activated Spawning (`ActivatedHabitatSettingsDTO`)
|
||||
Triggered spawning system - spawns occur based on specific triggers.
|
||||
|
||||
```kotlin
|
||||
trigger: Enum // REDSTONE, TICK, or RANDOM_TICK
|
||||
chance: Float = 1.0 // Probability (0.0-1.0) spawn attempt occurs on trigger
|
||||
cancelledNaturalSpawningRange: Int // Radius (blocks) where natural spawning is disabled
|
||||
spawnRange: Int // Radius (blocks) where spawning can occur
|
||||
maxSpawns: Int = -1 // Max concurrent spawns from this block (-1 = infinite)
|
||||
maxSpawnsPerActivation: Int = 1 // Max spawns per single trigger event
|
||||
habitatPool: HabitatPoolSettingsDTO // What Pokémon can spawn (see below)
|
||||
```
|
||||
|
||||
**Trigger Types:**
|
||||
- `REDSTONE`: Spawns on redstone pulse (rising edge)
|
||||
- `TICK`: Attempts spawn every game tick (very frequent)
|
||||
- `RANDOM_TICK`: Attempts spawn on random tick events
|
||||
|
||||
### Mode 2: Natural Spawning (`NaturalHabitatSettingsDTO`)
|
||||
Modifies the natural spawning system in the area.
|
||||
|
||||
```kotlin
|
||||
replaceSpawns: Boolean // true = only this pool spawns, false = adds to natural spawns
|
||||
rangeOfInfluence: Int // Radius (blocks) where this influences spawning
|
||||
habitatPool: HabitatPoolSettingsDTO // What Pokémon can spawn (see below)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Habitat Pool Settings (`HabitatPoolSettingsDTO`)
|
||||
|
||||
Defines what Pokémon can spawn. Can reference existing pools or define custom ones.
|
||||
|
||||
```kotlin
|
||||
id: ResourceLocation // Pool identifier
|
||||
isReference: Boolean // true = use existing pool, false = custom pool
|
||||
isActivated: Boolean // Must match parent spawning mode
|
||||
|
||||
// Only present when isReference = false:
|
||||
name: String? // Display name for custom pool
|
||||
spawns: List<HabitatSpawn>? // List of spawn entries
|
||||
```
|
||||
|
||||
**Pool Types:**
|
||||
- **Reference Pool**: `isReference = true` - Uses a pre-defined pool by ID (e.g., `cobblemon:forest_day`)
|
||||
- **Custom Pool**: `isReference = false` - Defines spawns inline with `name` and `spawns` list
|
||||
|
||||
**Custom Pool IDs**: Must start with `custom__` prefix (e.g., `cobblemon:custom__my_pool`)
|
||||
|
||||
---
|
||||
|
||||
## GUI Requirements
|
||||
|
||||
### Layout Sections
|
||||
|
||||
#### 1. Common Settings Panel
|
||||
- **Number of Phases**: Integer input greater than zero (default: 1)
|
||||
- **Phase Order**: Habitat Phase Order dropdown (default: SIMPLE)
|
||||
- **Level Range**: Two integer inputs (Min/Max) - Default: 1 to config max Pokémon level
|
||||
- **Modifiers**: Text input for PokemonProperties string
|
||||
- Examples: `shiny`, `gender=male`, `shiny gender=female level=50`
|
||||
- **Mimic Block**: Block selector/dropdown
|
||||
- Default: `minecraft:stone`
|
||||
- See `HabitatBlockEntity.mimicCycle` for suggested blocks
|
||||
|
||||
#### 2. Spawning Mode Selector
|
||||
Radio buttons or toggle:
|
||||
- **Activated Spawning** (trigger-based)
|
||||
- **Natural Spawning** (world spawning influenced)
|
||||
|
||||
#### 3. Mode-Specific Settings
|
||||
|
||||
**If Activated Spawning:**
|
||||
- **Trigger**: Dropdown (REDSTONE / TICK / RANDOM_TICK)
|
||||
- **Chance**: Float slider (0.0 - 1.0, default: 1.0)
|
||||
- **Cancel Natural Spawning Range**: Integer input (blocks)
|
||||
- **Spawn Range**: Integer input (blocks)
|
||||
- **Max Spawns**: Integer input (-1 for infinite, default: -1)
|
||||
- **Max Spawns Per Activation**: Integer input (default: 1)
|
||||
- **Habitat Pool**: Pool selector (see below)
|
||||
|
||||
**If Natural Spawning:**
|
||||
- **Replace Spawns**: Checkbox (true = exclusive, false = additive)
|
||||
- **Range of Influence**: Integer input (blocks)
|
||||
- **Habitat Pool**: Pool selector (see below)
|
||||
|
||||
#### 4. Habitat Pool Selector
|
||||
Two options:
|
||||
- **Use Existing Pool**: Dropdown of registered pools
|
||||
- Set `isReference = true`
|
||||
- Set `id` to selected pool
|
||||
- Ensure `isActivated` matches spawning mode
|
||||
- **Create Custom Pool**: Opens pool editor
|
||||
- Set `isReference = false`
|
||||
- Generate ID with `custom__` prefix
|
||||
- Set `name` and `spawns` list
|
||||
- User defines spawn entries (implementation depends on `HabitatSpawn` structure)
|
||||
|
||||
---
|
||||
|
||||
## Validation Rules
|
||||
|
||||
1. **Level Range**: Min must be ≥ 1, Max must be ≤ config max, Min ≤ Max
|
||||
2. **Number of Phases**: Must be greater than zero
|
||||
3. **Chance**: Must be between 0.0 and 1.0
|
||||
4. **Ranges**: All range values must be ≥ 0
|
||||
5. **Pool Validation**:
|
||||
- If `isActivated = true`, pool must be `ActivatedHabitatPool`
|
||||
- If `isActivated = false`, pool must be `NaturalHabitatPool`
|
||||
- If reference pool not found, server logs error and rejects settings
|
||||
6. **Custom Pool IDs**: Must start with `custom__`
|
||||
|
||||
---
|
||||
|
||||
## Network Flow
|
||||
|
||||
1. **Opening GUI**: Server sends `OpenHabitatBlockEditorPacket` with current `HabitatSettingsDTO`
|
||||
2. **Saving Changes**: Client sends updated `HabitatSettingsDTO` back to server
|
||||
3. **Server Processing**:
|
||||
- `HabitatBlockEntity.applySettings()` validates and applies changes
|
||||
- Calls `refreshFromSettings()` to regenerate spawn details
|
||||
- Marks block entity as changed and syncs to clients
|
||||
|
||||
---
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- **Creative Mode Only**: GUI should only be accessible to creative mode players
|
||||
|
||||
---
|
||||
|
||||
## Example Configurations
|
||||
|
||||
### Example 1: Redstone-Triggered Shiny Spawner
|
||||
```kotlin
|
||||
isActivatedSpawning = true
|
||||
phaseOrder = FIXED_RANDOM
|
||||
numberOfPhases = 4
|
||||
levelRange = 50..60
|
||||
modifiers = "shiny"
|
||||
mimicId = "minecraft:diamond_block"
|
||||
|
||||
activatedSettings:
|
||||
trigger = REDSTONE
|
||||
chance = 1.0
|
||||
spawnRange = 10
|
||||
maxSpawns = 1
|
||||
maxSpawnsPerActivation = 1
|
||||
habitatPool = (reference to existing pool)
|
||||
```
|
||||
|
||||
### Example 2: Natural Spawn Replacement Zone
|
||||
```kotlin
|
||||
isActivatedSpawning = false
|
||||
levelRange = 1..100
|
||||
phaseOrder = SIMPLE
|
||||
numberOfPhases = 1
|
||||
modifiers = ""
|
||||
mimicId = "minecraft:moss_block"
|
||||
|
||||
naturalSettings:
|
||||
replaceSpawns = true
|
||||
rangeOfInfluence = 32
|
||||
habitatPool = (custom pool with specific Pokémon)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Related Files
|
||||
- `HabitatBlockEntity.kt` - Main block entity logic
|
||||
- `HabitatSettingsDTO.kt` - Root settings container
|
||||
- `ActivatedHabitatSettingsDTO.kt` - Activated mode settings
|
||||
- `NaturalHabitatSettingsDTO.kt` - Natural mode settings
|
||||
- `HabitatPoolSettingsDTO.kt` - Pool configuration
|
||||
- `ActivatedHabitatSpawning.kt` - Activated spawning implementation
|
||||
- `NaturalHabitatSpawning.kt` - Natural spawning implementation
|
||||
@@ -1,9 +0,0 @@
|
||||
IVs layer
|
||||
Move layer
|
||||
Remove nature layer in favour of modification layer
|
||||
Reconsider form layer. Its timing seems more important than anything else
|
||||
Remove cosmetic layer
|
||||
Add shiny layer
|
||||
|
||||
Fix the way the client is the one deciding when hatching will happen from that TriggerEggHatchHandler
|
||||
Clean up duplication in hatchPokemon logic for nest and incubator, should be a common function in EggComponent probably for hatching into a player's party
|
||||
+2
-5
@@ -1,6 +1,3 @@
|
||||
import utilities.gitBranch
|
||||
import utilities.gitShortCommit
|
||||
|
||||
plugins {
|
||||
id("cobblemon.root-conventions")
|
||||
}
|
||||
@@ -9,6 +6,6 @@ version = "${project.property("mod_version")}+${project.property("mc_version")}"
|
||||
|
||||
val isSnapshot = project.property("snapshot")?.equals("true") == true
|
||||
if (isSnapshot) {
|
||||
val fixedBranchName = gitBranch().substringAfter("/")
|
||||
version = "$version-${fixedBranchName}-${gitShortCommit()}"
|
||||
val fixedBranchName = versioning.info.branch.substringAfter("/")
|
||||
version = "$version-${fixedBranchName}-${versioning.info.build}"
|
||||
}
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
# Changelog
|
||||
## [1.7.2 (January 25th, 2026)](#1-7-2)
|
||||
|
||||
### Additions
|
||||
- Added Saccharine wood furniture for Adorn.
|
||||
- Added the Partner Mark, which party Pokémon have a very small chance to earn as the player walks, provided they have enough friendship.
|
||||
- Added decorative block models for existing items: Potion, Super Potion, Hyper Potion, Max Potion, Full Restore, Antidote, Awakening, Burn Heal, Ice Heal, Paralyze Heal, Full Heal, Ether, Elixir, Max Ether, Max Elixir, X Accuracy, X Attack, X Defence, X Special Attack, X Special Defence, X Speed, Dire Hit, Guard Spec, Weakness Policy, Blunder Policy, Cleanse Tag, and Spell Tag.
|
||||
- Added decorative sign blocks called Plaques.
|
||||
- Added ride style labels to ride stats in Pokédex, as well as ride style icons in the summary GUI.
|
||||
- Added more seasonings for sinister tea:
|
||||
- Mental Herb - Mental Restoration I for 10 seconds, which staves off Insomnia.
|
||||
- White Herb - Removes negative effects.
|
||||
- Milk, Moomoo Milk - Removes effects.
|
||||
- Added dispenser support for:
|
||||
- Applying a Honey Bottle to Saccharine Logs.
|
||||
- Washing honey off of Saccharine Slathered Logs.
|
||||
- Applying and removing honey on Saccharine Leaves.
|
||||
- Added riding statistics: `Distance by Pokémon on Land`, `Distance by Pokémon in Air` and `Distance by Pokémon in Liquid`.
|
||||
|
||||
### New rideable Pokémon
|
||||
- Honchkrow
|
||||
- Mantine
|
||||
|
||||
### Pokémon Added
|
||||
|
||||
#### Gen 5
|
||||
- Throh
|
||||
- Sawk
|
||||
|
||||
#### Gen 6
|
||||
- Litleo
|
||||
- Pyroar
|
||||
- Spritzee
|
||||
- Aromatisse
|
||||
- Swirlix
|
||||
- Slurpuff
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
- Falinks
|
||||
- Cottonee
|
||||
- Whimsicott
|
||||
- Ferroseed
|
||||
- Ferrothorn
|
||||
- Chingling
|
||||
- Chimecho
|
||||
|
||||
### Animation updates for the following Pokémon
|
||||
- Mantine (ride animations)
|
||||
- Flygon (ride jump animation)
|
||||
- Honchkrow (ride animations)
|
||||
- Croagunk
|
||||
- Toxicroak
|
||||
|
||||
### Changes
|
||||
- Added a new config option, `Enable In-Flight Dismounting` (default: off), which lets you dismount while riding a Pokémon in the air. This is the textbook definition of caveat emptor.
|
||||
- Ride sounds have been separated into stereo for passengers and mono for other players. Riding will now sound more spacious.
|
||||
- Battle AI now uses a smarter threshold for switching, reducing unnecessary switches.
|
||||
- AI will always use the most damaging move when at low HP and when it is not switching, improving endgame decision-making.
|
||||
- Items given from interacting with Saccharine Leaves are placed in the active hotbar slot if possible.
|
||||
- Added `label` as an alternate key to the `tag` property.
|
||||
|
||||
### Fixes
|
||||
- Fixed crashing when viewing another player in spectator mode. Some said this was reason to release this update a month ago. They were probably right.
|
||||
- Fixed crashing when sending a Pokémon out after editing its form.
|
||||
- Fixed all Pokémon being saved to chunks and never despawning even when they should be.
|
||||
- Fixed Poké Snacks crashing if there was no available spawn.
|
||||
- Fixed Poké Snack / Bait effects so that EV Yield, Type, and Egg Group filters now all apply together when weighting spawns. And you thought you were going crazy.
|
||||
- Fixed Furfrou not being trimmable on NeoForge specifically.
|
||||
- Fixed honey from Saccharine Leaves being harvestable at less than the max age.
|
||||
- Fixed possible error on world generation when Combee are placed in naturally generated bee nests.
|
||||
- Fixed Galarian Weezing crashing the world if it decides to blink the wrong way. The same could happen to you!
|
||||
- Fixed Galarian Mr. Mime incorrectly being rideable. Some would argue that regular Mr. Mime shouldn't be rideable, but that would make them wrong.
|
||||
- Fixed missing apricorn textures for Adorn blocks.
|
||||
- Fixed Apricorn block model rotation for counters/sinks/cupboards/drawers to match that of most recent version of Adorn.
|
||||
- Fixed item interaction sometimes not working properly when playing on servers.
|
||||
- Fixed Mint Leaves not being usable for filling the Resurrection Machine.
|
||||
- Fixed Super Potion recipes incorrectly using Hondew Berry instead of Aguav Berry. They look similar, to be fair.
|
||||
- Fixed Wishiwashi not schooling properly.
|
||||
- Fixed battle item duplication issue. How did it work? Wouldn't you like to know, weather boy.
|
||||
- Fixed the ordering of Aprijuice's riding stat boosts so they always have the same order.
|
||||
- Fixed the movesets of certain Pokémon being incorrectly sanitized upon reload, causing some forms to keep losing moves.
|
||||
- Fixed selected leading Pokémon in battle not being used when levels are set.
|
||||
- Fixed the bottom half of pasture blocks having an incorrect hit-box when facing north or south.
|
||||
- Fixed gimmicks not being usable in double and triple battles.
|
||||
- Fixed gimmick buttons showing when already used in the same turn in double and triple battles.
|
||||
- Fixed mochi items consuming two items at a time.
|
||||
- Fixed Fresh Start Mochi's EV reset not syncing health changes properly.
|
||||
- Fixed Pokémon spawn influences not being specific to regional forms.
|
||||
- Fixed memory leak from battles not being cleaned up after ending.
|
||||
- Fixed orientation not getting reset after crashing while flying and getting back on the Pokémon.
|
||||
- Fixed shiny Pokémon not respecting the `silent` flag on spawn.
|
||||
- Fixed 'Plain' prefix not being applied to all low-quality Aprijuice.
|
||||
- Fixed Pokémon interactions not playing sound effects when the volume was not specified.
|
||||
- Fixed Pokémon interaction cooldowns taking longer than intended when the Pokémon was in the player’s party.
|
||||
- Fixed Pokémon interactions occasionally crashing the game when spamming an interaction with a 0 cooldown.
|
||||
- Fixed Pokémon fullness decreasing more than intended when the Pokémon was pastured.
|
||||
- Fixed Scraggy line, Milcery line, and Morpeko spawning on unnatural blocks.
|
||||
- Fixed invulnerability-bypassed damage being resisted by invulnerable NPC entities.
|
||||
- Fixed Fabric network packets not being handled immediately, fixing incompatibilities with Supplementaries, Prometheus, Sleep Tight, and others.
|
||||
- Fixed killer not being set early enough on a wild Pokémon entity from `WinInstruction`.
|
||||
- Fixed requirements such as `biomeCondition` crashing the game when used to define Pokémon interactions.
|
||||
- Fixed an issue that prevented registering custom dispenser behaviours (no longer overrides vanilla behaviour).
|
||||
- Fixed an issue navigation that prevented Combee from pathing into and out of Saccharine Leaves.
|
||||
- Added Saccharine Boats and Saccharine Boat with Chests to relevant boat tags.
|
||||
- Fixed Soothe Bell not being properly tagged as a held item.
|
||||
- Fixed `/calculateseatpositions` expecting a locator format that even we don't use. It needs an underscore after "seat".
|
||||
- Fixed the `run_script` Molang function to not fail if the environment's context is null.
|
||||
- Fixed the Molang functions `date_local_time`, `date_of`, `date_is_after` to use the correct date format.
|
||||
|
||||
### Developer
|
||||
- Changed the `owner` parameter in the `OwnerQueryRequirement` interface from `ServerPlayer` to `Player`. This method is now also called on the client to verify whether a Pokémon interaction succeeded, so make sure to update your implementations to handle both server and client contexts.
|
||||
- Added the `pnx` to the `BattleFaintedEvent` and `FormeChangeEvent`.
|
||||
- Added register methods for custom instructions to `ShowdownInterpreter`.
|
||||
- Changed callback operations in `BattlePokemon` to allow multiple callbacks and be mutable.
|
||||
- Added `display_name`, `description`, and `max_pp` functions to the `MoveTemplate` struct.
|
||||
- Changed the implementations of `AIBattleActor` to be open classes to allow extension.
|
||||
- Changed the resource location of Poké Ball icons in the GUI to use the balls namespace instead of Cobblemon's, allowing mods to properly use their own namespace for these textures.
|
||||
|
||||
### Molang & Datapacks
|
||||
- Ride sounds can now be set as exclusive to passengers.
|
||||
- Ride sounds no longer play when submerged unless specified with a new setting.
|
||||
- Exception handling has been added to `run_molang`, resolving some crashes caused by malformed MoLang expressions.
|
||||
- Added the `create_itemstack`, `has_inventory_space`, `set_inventory_slot`, and `give_item` MoLang functions for item and inventory utility.
|
||||
- Added the `get_move_from_id` MoLang function for general move info queries without requiring a Moveset object to access.
|
||||
- Added support for optional message variants in battle activate instructions for more context-specific battle text.
|
||||
- Example: `this.add('-activate', pokemon, 'ability: example', '[msg]message1');` will parse to lang key `cobblemon.battle.activate.example.message1`.
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- French
|
||||
- Canadian French
|
||||
- Simplified Chinese
|
||||
- Ukrainian
|
||||
- Brazilian Portuguese
|
||||
- Spanish
|
||||
- Korean
|
||||
- Japanese
|
||||
@@ -1,22 +0,0 @@
|
||||
# Changelog
|
||||
## [1.7.3 (January 31st, 2026)](#1-7-3)
|
||||
|
||||
### Fixes
|
||||
- Fixed mounted Pokémon not playing sounds.
|
||||
- Fixed players failing to join servers randomly.
|
||||
- Fixed some Pokémon having no stamina for flying.
|
||||
- Fixed `/pctake` not respecting the actual size of the PC.
|
||||
### Developer
|
||||
- Poké Ball GUI textures now respect the ball's namespace, enabling proper texture loading for custom balls from other mods.
|
||||
|
||||
### Molang & Datapacks
|
||||
- Added a `chance` requirement type for Pokémon interactions.
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- French
|
||||
- Canadian French
|
||||
- Korean
|
||||
- Portuguese
|
||||
- Simplified Chinese
|
||||
- Spanish
|
||||
@@ -1,529 +0,0 @@
|
||||
# Changelog
|
||||
## [1.8.0 - Make Your Move Update (September 6th, 2026)](#1-8-0)
|
||||
#### I think the red eyes mean they're friendly!
|
||||
|
||||
### Additions
|
||||
- Added Alpha Pokémon
|
||||
- Alpha Pokémon are bigger, stronger, and more aggressive than regular Pokémon.
|
||||
- They are also scarier.
|
||||
- They always know a TM move and will adapt to be stronger than your party.
|
||||
- Alphas will always lead herds and spawn in herds.
|
||||
- Added alpha Pokémon attraction bait effect to Hopo Berries.
|
||||
- Added intrinsic scaling to all Pokémon (anywhere from 5% smaller to 5% bigger than normal). Some cases, such as shoulder mounting, will not scale so that the shoulder animations don't look silly.
|
||||
- Added scaling to "baby" Pokémon (10% smaller at level 1 → normally sized at level 10).
|
||||
- Added TMs.
|
||||
- Added TM Machine. TMs are made from elemental type gems, and their recipes are unlocked by having Pokémon that know the move.
|
||||
- Added config options for making TMs infinite-use and instant unlocking of all TM recipes.
|
||||
- Added Type Gem blocks as well as crystal clusters and deepslate core blocks that are used for growing elemental type gems.
|
||||
- Added a new Starter Selection menu that looks way better.
|
||||
- Added a "Move Dex" to the Pokédex to help identify what moves a Pokémon can learn and what Pokémon can get a move.
|
||||
- Added the Habitat Block, a spawner block for servers and adventure maps that controls spawning in an area.
|
||||
- Added 49 new habitat structures. In these habitats you will find rarer Pokémon and sometimes different Pokémon will appear on different days.
|
||||
- Added a toast to notify players of how they can scroll through their party. Did you know you can hold R and scroll instead of using arrow keys? It's true!!!
|
||||
- Added a way to obtain Porygon by inserting an Upgrade or Dubious Disc into a data monitor.
|
||||
- Added Disk Rack for storing disks and being an audio sequencer for Noteblocks. What does that have to do with Pokémon? How about you mind your own business!
|
||||
- Added missing crops to Botany Pots integration.
|
||||
- Added conditional seats for riding. Seats can be gated by Molang such as "is_alpha".
|
||||
- Added 10 new ruin structures.
|
||||
- Added a new shipwreck cove structure called the Magma Shipwreck Cove.
|
||||
- Added 7 new advancements.
|
||||
- Pokémon cries now play when clicking Pokémon in the summary screen.
|
||||
- Held item visibility can now be controlled by the `held_item_visible` command argument.
|
||||
- Added config option to disable Pokémon spawning on a per-world basis.
|
||||
- Added config options to award experience to fainted Pokémon for opponents they helped defeat (`awardExperienceToFaintedPokemon`) and to still award experience for defeated enemies even after battle loss/forfeit (`awardExperienceOnBattleLoss`).
|
||||
- Added `/givetm` command.
|
||||
- Added advancement triggers for learning TMs: `cobblemon:has_learn_specific_tm` (per-TM), `cobblemon:has_learn_all_tm` (all TMs learned), and `cobblemon:tms_learned` (count-based), backed by a new `totalTMLearnedCount` on player advancement data.
|
||||
- Added `cobblemon:catch_alpha_pokemon` advancement trigger and `totalAlphaCaptureCount` stat for captured Alpha Pokémon.
|
||||
|
||||
### New rideable Pokémon
|
||||
- Crobat
|
||||
- Skarmory
|
||||
- Milotic
|
||||
- Archeops
|
||||
- Goodra
|
||||
- Goodra (Hisuian Form)
|
||||
- Drampa
|
||||
- Duraludon
|
||||
- Archaludon
|
||||
|
||||
### Pokémon Added
|
||||
#### Generation 3
|
||||
- Wurmple
|
||||
- Silcoon
|
||||
- Beautifly
|
||||
- Cascoon
|
||||
- Dustox
|
||||
- Skitty
|
||||
- Delcatty
|
||||
- Seviper
|
||||
- Zangoose
|
||||
|
||||
#### Generation 4
|
||||
- Cherubi
|
||||
- Cherrim
|
||||
- Stunky
|
||||
- Skuntank
|
||||
|
||||
#### Generation 5
|
||||
- Audino
|
||||
- Pawniard
|
||||
- Bisharp
|
||||
|
||||
#### Generation 6
|
||||
- Pancham (+ Cosmetic with Black Glasses)
|
||||
- Pangoro (+ Cosmetic with Black Glasses)
|
||||
|
||||
#### Generation 7
|
||||
- Rockruff
|
||||
- Lycanroc
|
||||
|
||||
#### Generation 8
|
||||
- Rolycoly
|
||||
- Carkol
|
||||
- Coalossal
|
||||
- Runerigus
|
||||
- Snom
|
||||
- Frosmoth
|
||||
- Indeedee
|
||||
- Duraludon
|
||||
- Applin
|
||||
- Flapple
|
||||
- Appletun
|
||||
|
||||
#### Generation 9
|
||||
|
||||
- Nymble
|
||||
- Lokix
|
||||
- Kingambit
|
||||
- Dipplin
|
||||
- Archaludon
|
||||
- Hydrapple
|
||||
|
||||
#### Regional Forms
|
||||
- Sandshrew (Alolan Form)
|
||||
- Sandslash (Alolan Form)
|
||||
- Yamask (Galarian Form)
|
||||
- Avalugg (Hisuian Form)
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
|
||||
- Sandshrew
|
||||
- Sandslash
|
||||
- Nidoking
|
||||
- Zubat
|
||||
- Golbat
|
||||
- Crobat
|
||||
- Ditto
|
||||
- Porygon
|
||||
- Porygon2
|
||||
- Porygon-Z
|
||||
- Skarmory
|
||||
- Smoochum
|
||||
- Jynx
|
||||
- Popplio
|
||||
- Brionne
|
||||
- Primarina
|
||||
- Fletchling
|
||||
- Fletchinder
|
||||
- Talonflame
|
||||
- Sableye
|
||||
- Mawile
|
||||
- Goomy
|
||||
- Sliggoo
|
||||
- Goodra
|
||||
- Nacli
|
||||
- Naclstack
|
||||
- Garganacl
|
||||
- Bidoof
|
||||
- Cranidos
|
||||
- Chatot
|
||||
- Yamask
|
||||
- Cofagrigus
|
||||
- Tyranitar
|
||||
- Turtonator
|
||||
- Golett
|
||||
- Corsola
|
||||
- Arbok (New Patterns: Angry, Cartoon, Clown, Comedic, Crow, Grin, Ink, Modern, Rain, Scribble, Silence, Sloth, Suspicious, Will)
|
||||
- ... and Substitute
|
||||
|
||||
#### Model changes to the regional bias resource pack:
|
||||
- Added Mime Jr. (Galar Bias)
|
||||
- Added Bergmite (Hisui Bias)
|
||||
- Changed models for every existing regional bias
|
||||
|
||||
### Animation updates for the following Pokémon
|
||||
|
||||
- Kakuna
|
||||
- Grimer
|
||||
- Nidoran♀ (+ New shoulder mount)
|
||||
- Nidorina
|
||||
- Nidoran♂ (+ New shoulder mount)
|
||||
- Sandshrew
|
||||
- Diglett
|
||||
- Dugtrio
|
||||
- Graveler
|
||||
- Happiny
|
||||
- Chansey
|
||||
- Blissey
|
||||
- Poliwhirl
|
||||
- Poliwrath
|
||||
- Zubat
|
||||
- Vulpix
|
||||
- Drowzee
|
||||
- Hypno
|
||||
- Noctowl
|
||||
- Skarmory
|
||||
- Skitty
|
||||
- Flygon
|
||||
- Shellos
|
||||
- Riolu
|
||||
- Lucario
|
||||
- Purrloin
|
||||
- Liepard
|
||||
- Joltik
|
||||
- Galvantula
|
||||
- Nidoking
|
||||
- Fletchling
|
||||
- Fletchinder
|
||||
- Talonflame
|
||||
- Archeops
|
||||
- Drampa
|
||||
- Sewaddle
|
||||
- Swadloon
|
||||
- Leavanny
|
||||
- Goomy
|
||||
- Sliggoo
|
||||
- Goodra
|
||||
- Shedinja
|
||||
- Skwovet
|
||||
- Greedent
|
||||
- Bidoof
|
||||
- Cranidos
|
||||
- Chatot
|
||||
- Yamask
|
||||
- Cofagrigus
|
||||
- Luvdisc
|
||||
- Staryu
|
||||
- Starmie
|
||||
- Togetic
|
||||
- Rellor
|
||||
- Rabsca
|
||||
- Yungoos
|
||||
- Gumshoos
|
||||
- Cottonee
|
||||
- Whimsicott
|
||||
- Corsola
|
||||
|
||||
#### Added sounds to the following moves
|
||||
|
||||
- Absorb
|
||||
- Aurora Beam
|
||||
- Double Team
|
||||
- Draco Meteor
|
||||
- Fire Punch
|
||||
- Fire Spin
|
||||
- Flame Charge
|
||||
- Flame Wheel
|
||||
- Giga Drain
|
||||
- Ice Punch
|
||||
- Leech Life
|
||||
- Magical Leaf
|
||||
- Mega Drain
|
||||
- Minimize
|
||||
- Poison Gas
|
||||
- Rock Throw
|
||||
- Scary Face
|
||||
- Seed bomb
|
||||
- Smokescreen
|
||||
- String Shot
|
||||
- Tail Whip
|
||||
|
||||
### Changes
|
||||
- Removed the penalty for block destruction speed when on a hover mount, making them better for digging.
|
||||
- Golden Apples can now be crafted using the Applin Apples.
|
||||
- Prismarine Crystals and Amethyst Shards can now be used to craft Pokedexes.
|
||||
- Updated Pokédex Screens item tag to support tagged variants of Redstone and Glowstone Dust.
|
||||
- Sharp Beak can now be crafted using bones and Flying Gems.
|
||||
- Metal Alloy can now be crafted using iron and Thunder Stones.
|
||||
- Ability Capsules can now be brewed from Medicinal Brew and Dragon Breath.
|
||||
- Using an Ability Capsule will now return an Empty Bottle.
|
||||
- Decreased the default pastured wander radius to 32 blocks.
|
||||
- Added alternate versions of the basic PC Wallpapers based on the original design of Cobblemon's PC, before public release.
|
||||
- Rooted Arch Ruins, Crumbling Arch Ruins, and all fossil structures have been improved so that they generate more naturally in terrain.
|
||||
- Gimmighoul towers now generate at ground-level rather than sinking one block into the ground.
|
||||
- All ruin structures that did not generate with a gimmighoul/gilded chest before will now generate with one.
|
||||
- All ruin structures gilded chest loot tables have been updated to include a guaranteed TM not learned naturally by any Pokémon through their level-up moveset. Each ruin gets its own specific TM, so you can now go hunting ruins to complete your move dex!
|
||||
- The Prehistoric Underwater Fissure and Prehistoric Submerged Impact fossil structures now use the biome tag `#cobblemon:is_temperate_ocean`.
|
||||
- The lush shipwreck cove's phantom mob spawner has been replaced with breezes.
|
||||
- Shipwreck coves now generate slightly more frequently.
|
||||
- Added equipment loot tables for shipwreck cove enemies.
|
||||
- Maps from abandoned fishing boats leading to shipwreck coves now will skip explored chunks, allowing the player to find more shipwreck coves more easily.
|
||||
- All shipwreck coves' spawners have been adjusted to give compatible mobs enchanted iron or diamond armour and weapons while in its ominous state. The armour given to the mobs will also use the automaton trim. We upped the difficulty because it was too easy now that your Pokémon can fight for you.
|
||||
- One TM of the elemental hyper beams has been added as guaranteed loot to the main treasure chest in every shipwreck cove. (Magma Cove gets Blast Burn, Lush Cove gets Frenzy Plant, and Submerged Cove gets Hydro Cannon.)
|
||||
- The following items can now be obtained by brushing the following Pokémon:
|
||||
- Pink Wool - Wigglytuff
|
||||
- White Wool - Swablu, Altaria
|
||||
- Shed Shell - Ekans, Arbok, Dratini, Dragonair, Dunsparce, Treecko, Grovyle, Sceptile, Seviper, Scraggy, Scrafty, Helioptile, Heliolisk, Salandit, Salazzle, Sobble, Drizzile, Inteleon, Silicoblra, Sandaconda, Toxel, Toxtricity, Orthworm, Dudunsparce
|
||||
- Phantom Membrane - Dreepy, Drakloak, Dragapult
|
||||
- The following items can now be obtained by evolving the following Pokémon into any of their evolutions:
|
||||
- Turtle Scute - Squirtle, Wartortle, Turtwig, Grotle, Tirtouga, Chewtle
|
||||
- Shed Shell - Metapod, Kakuna, Ekans, Paras, Venonat, Krabby, Scyther, Kabuto, Dratini, Dragonair, Ledyba, Spinarak, Yanma, Pineco, Dunsparce, GLigar, Pupitar, Treecko, Grovyle, Silcoon, Cascoon, Surskit, Nincada, Trapinch, Vibrava, Corphish, Anorith, Bagon, Shelgon, Kricketot, Burmy, Combee, Skorupi, Swadloon, Whirlipede, Dwebble, Scraggy, Karrablast, Joltik, Larvesta, Spewpa, Clauncher, Helioptile, Charjabug, Crabrawler, Cutiefly, Dewpider, Salandit, Wimpod, Poipole, Sobble, Drizzile, Dottler, Silicobra, Toxel, Sizzlipede, Snom, Tarountula, Nymble, Rellor
|
||||
- Saccharine Leaves now drop Tart, Sweet, or Syrupy Apples, depending on their honey coating stage, instead of vanilla Apples.
|
||||
- Fixed the height of the Tumblestone Bud items when held in hand, placed on head, viewed in a GUI, and placed in an Item Frame.
|
||||
- Refactored all advancements, removing several deemed unnecessary. Due to this cleanup, all previously obtained advancements will be reset besides the root (for picking a starter Pokémon). This sucks, and we're sorry. We had to do this eventually so better now than later.
|
||||
- Forces between colliding hitboxes now factors in the weight of Pokémon.
|
||||
- Improved berry tree performance on singleplayer and servers.
|
||||
- Updated stat increase and decrease particle effects with the addition of alpha boost particles.
|
||||
- Improved the performance of pasture blocks on singleplayer and servers.
|
||||
- Changed the bait effects of the following items: (Vanilla) Sweet & Glow Berries, Golden & Enchanted Golden Apples (Cobblemon) Custap, Eggant, Hopo & Micle Berries, Sweet Hearts.
|
||||
- Wild Pokémon now reliably have at least one offensive move if they can have offensive moves at that level. No more free lunches with Pokémon that can't even hurt you.
|
||||
- Data Monitor can accept Disks (TMs, Music Disks, Upgrade, Dubious Disk, etc.) to change what's being displayed on the screen.
|
||||
- The party overlay's experience-gained animation now displays the amount of EXP the Pokémon gained.
|
||||
- Pressing the inventory key now closes the Pokémon interact wheel GUI.
|
||||
- Updated the sound for harvesting Apricorns.
|
||||
- Lowered the volume of harvesting berries.
|
||||
- Improved compatibility with various mods
|
||||
- Farmer's Delight's cutting board can now be used to strip Apricorn and Saccharine's logs, or salvage their planks from various blocks. It can also separate their boats from chests.
|
||||
- Farmer's Delight's cutting board can be used to get two white dye from Pep-Up Flowers and two magenta dye from Medicinal Leeks.
|
||||
- Farmer's Delight's cutting board can separate Tumblestone Blocks back into Tumblestones.
|
||||
- Farmer's Delight's cutting board can salvage Type Gems from their Gem Blocks.
|
||||
- Farmer's Delight's Onions, Tomatoes, and Cabbages can be used to cook Open-Faced Sandwiches. Nature's Spirit's Olives also can be used.
|
||||
- Farmer's Delight's cutting board can be used on Hearty Grains to obtain rice and straw, similarly to Farmer's Delight's Rice Panicles.
|
||||
- Farmer's Delight's Apple Pies and Apple Ciders can now be made using Applin Apples, alongside the Vanilla counterpart.
|
||||
- Amendments allows for cooking Leek and Potato Stew in a Cauldron.
|
||||
- Any mods that utilise Moonlight's Soft Fluid system can store Leek and Potato Stew, Medicinal Brew, Antidote, Awakening, Burn Heal, Ice Heal, Paralyze Heal, Full Heal, Potion, Super Potion, Hyper Potion, Max Potion, Full Restore, Ability Capsules, Moomoo Milk, and Berry Juice in liquid form (such as Suplementaries' Jar or Goblet, or Cauldrons while using Amendments).
|
||||
- Supplementaries' Hourglass can now use Bright Powder, Quick Powder, Metal Powder, Heal Powder, Silver Powder, and Remedy.
|
||||
- Berry Trees are now compatible with the Planter properly
|
||||
- Saccharine Way Signs (added by Supplementaries automagically) now use a premade texture to prevent odd visual issues.
|
||||
- Supplementaries' Jar can now store various Cobblemon cookies, candies, and similar items.
|
||||
- Some of Supplementaries' items have been added to the `#cobblemon:held/container_held_items` item tag, including sacks, safes, and lunch baskets.
|
||||
- Experience Nuggets can be used in place of Sculk for making the EXP Candies if using Create.
|
||||
- Rage Candy Bar has a Create Mixing recipe.
|
||||
- All Cobblemon ores can now be crushed in Create's Crushing Wheels. All Gem and Tumblestone Clusters can be crushed for automatic, low return, gems.
|
||||
- Hearty Grains can be milled like Farmer's Delight Rice Panicles if both Farmer's Delight and Create are installed.
|
||||
- Big Roots and Revival Herbs can be milled to their respective powders.
|
||||
- Pep-Up Flowers, Medicinal Leeks, and all 70 berries can be milled in Create's Millstone for additional dye drops.
|
||||
- Auspicious Armour and Upgrades can be Haunted using Create's crafting systems.
|
||||
- Applin Apples can be used to make Honeyed Apples in Create.
|
||||
- Sounds for interacting with various Cobblemon blocks now play from the centre of the block, rather than the corner. You probably didn't notice.
|
||||
- Dragonite's mailbag cosmetic can now also be obtained with a chest in the cosmetic slot.
|
||||
- Adjusted the walk speed for Croagunk and Aerodactyl.
|
||||
- The `/pc` command no longer plays PC activation sounds
|
||||
- Pressing the Summary key while either the starter selection or summary screen are open now closes those screens.
|
||||
- Ice type Pokémon are now immune to Packed Snow.
|
||||
- Added cobweb block slowness immunity for spider Pokémon
|
||||
|
||||
### Fixes
|
||||
- Fixed rare Pokémon being far too likely to spawn multiple times in a single spawn cycle. The dev told me that the exact bug is too complicated to explain.
|
||||
- Fixed Omanyte and Omastar incorrectly using water animations on land.
|
||||
- Fixed Pokédex layout for genderless variations.
|
||||
- Fixed odd stacking behaviour with Poké Baits.
|
||||
- Fixed a compatibility issue with World Game Rules which caused some log spam in specific cases.
|
||||
- Fixed improper validation of Pokémon when performing a trade.
|
||||
- Fixed an issue where particles like beams can disappear when you don't see the beginning of the beam, or you look away.
|
||||
- Fixed Bedrock particle materials sometimes being incorrectly invisible from some sides.
|
||||
- Fixed an occasional crash on retrieving revived fossils.
|
||||
- Fixed brushing not working on Neoforge. Again.
|
||||
- Fixed braking not working for submarine-style mounts (whoops).
|
||||
- Fixed strafing not having the same friction as forward movement (funny whoops).
|
||||
- Fixed submarine-style mounts' surface-water animations not playing when supposed to.
|
||||
- Fixed submarine-style mounts' camera freaking out when looking up or down on the surface.
|
||||
- Fixed pastured Pokémon despawning and running away.
|
||||
- Fixed Apricorn trees crashing when other mods bonemeal them.
|
||||
- Fixed the issue that caused hover-style mounts without a ground style to be rendered useless upon touching the ground on a server.
|
||||
- Fixed horizontal and vertical collisions with hover-style mounts so they no longer accumulate or retain momentum.
|
||||
- Fixed NeoForge brewing stand unexpectedly crashing users when shift clicking items within its menu. Well, I suppose all crashes are unexpected. You know what I mean.
|
||||
- Fixed NPCs switching Pokémon very often during battles.
|
||||
- Fixed Campfire Pot causing crashes under certain circumstances.
|
||||
- Fixed Type Gems not being consumed upon use in battles.
|
||||
- Fixed several Ancient Pokéball's not using the correct capture multiplier.
|
||||
- Fixed a server warning that could occur when recalling Pokémon.
|
||||
- Fixed sliding particles incorrectly handling block collision.
|
||||
- Fixed Full Heal not curing status conditions in battle. Literally it's one job.
|
||||
- Fixed a rare issue with battles locking up when you are forced to switch, with the switch menu appearing instantly.
|
||||
- Fixed the combined effects of Pledge moves having broken Showdown message handling and localisation.
|
||||
- Fixed a very niche issue where structures would spawn in an incorrect location, creating very funky world gen.
|
||||
- Fixed Galarian Ponyta missing its cry.
|
||||
- Fixed various log warnings caused by redundant files and sound events.
|
||||
- Traded Pokémon will now retain the original friendship level when traded back to its OT.
|
||||
- Tumblestone Clusters now display correctly on maps.
|
||||
- Fixed removing mulch from berry trees with a shovel not working. That was meant to be a thing.
|
||||
- Fixed collecting honey from Saccharine Leaf blocks deleting Honey Bottles when the inventory was full.
|
||||
- Fixed Stripped Saccharine Wood recipe being... not there.
|
||||
- Fixed some performance issues with a kind of sound event causing lag by attempting to create sounds every tick when out of range of hearing.
|
||||
- Fixed stat-reducing Aprijuice not being possible to apply on a maxed out Pokémon. Also fixed the possibility of going into negatives.
|
||||
- Fixed exploit where you could take out the bait or drop your Pokérod with bait to avoid consuming bait, now the bobber will just disappear if you do so.
|
||||
- Fixed Apricorn and Saccharine boats incorrectly using chest boat models.
|
||||
- Fixed wild and trainer battle AI refusing to select moves with the `adjacentAlly` target type, even when it's their only option.
|
||||
- Fixed gilded chests being more accessible than intended.
|
||||
- Fixed fished up Pokémon not being added as "seen" to the Pokédex.
|
||||
- Fixed surprised Gimmighoul encounters not being added as "seen" to the Pokédex.
|
||||
- Fixed a crash involving berry trees that have been world edited.
|
||||
- Fixed visual desync in multiplayer for players mounting Pokémon outside other players' loaded chunks.
|
||||
- Fixed Pokémon entities leveled by rare candy not getting stronger as Minecraft entities unless recalled.
|
||||
- Fixed a freeze during game load that occurred when multiple mods tried to load Cobblemon API classes at the same time.
|
||||
- Lowered the volume of Blitzle and Zebstrika's cry (shut up!).
|
||||
- Regional Foods will now prioritise being eaten instead of used for healing Pokémon - shift clicking will use it as healing.
|
||||
- Resolved z-fighting (texture flickering) on Pokédex Models.
|
||||
- Restored Ninjask's ability to do barrel rolls.
|
||||
- Fixed Raichu (male) and Alolan Raichu (both genders) not displaying the correct Partner Cap when Pewter Crunchies are in the cosmetic slot.
|
||||
- Fixed a crash caused by adding enchanted items to the Resurrection Machine.
|
||||
- Fixed a crash that could occur when starting a PvN battle with only fainted Pokémon.
|
||||
- Fixed the Remember Riding Camera config not being respected when dismounting and resolved the incompatibility with the Auto Third Person mod.
|
||||
- Fixed Full Heal block not dropping Full Heals. Lmao.
|
||||
- Fixed status cure items not returning an empty bottle when used.
|
||||
- Fixed Panpour consuming its held item when evolving with a Water Stone.
|
||||
- Fixed Smoked Tail Curry returning a Wooden Bowl when consumed despite it not being included in the recipe. Free bowls!
|
||||
- Fixed `/giveallpokemon` not respecting the min and max arguments.
|
||||
- Fixed the choose starter toast not disappearing when capturing a Pokémon instead of opening the starter selection screen.
|
||||
- Fixed an issue where certain Sinister Tea seasonings were only applying as instant effects and would not apply over time.
|
||||
- Long config option labels now scroll instead of overflowing in the configuration menu.
|
||||
- Fixed some z-fighting and clipping on Dewott and Hisui-Bias Dewott.
|
||||
- Eggant Berries can now be composted properly on NeoForge.
|
||||
- Composting chances are now the same on NeoForge as on Fabric.
|
||||
- Fixed problem where furnaces which had smelted Revival Herbs into Heal Powder in older versions would glitch out on trying to get the experience out of the block.
|
||||
- Fixed the Battle AI not recognizing Surging Strikes as a multistrike move.
|
||||
- Fixed Tentacool not using its swim animation when on water surface.
|
||||
- Fixed Eevee using its left shoulder pose when in battle.
|
||||
- Fixed Magikarp and Gyarados Jump Pattern resourcepacks replacing shiny textures of addons targeting Magikarp or Gyarados.
|
||||
- Fixed Combee's pollinated texture overwriting the shiny and female textures.
|
||||
- Fixed a colour mistake with Dracovish's shiny.
|
||||
- Fixed Togedemaru's back spikes z-fighting.
|
||||
- Fixed Sliggoo (+ Hisuian) evolving in the Nether and End where it can't actually rain.
|
||||
- Corrected the scales, hitbox sizes, and eye heights for Ariados, Cetoddle, Durant, Galvantula, Klink, Lanturn, Lumineon, Mantine, Mantyke, Mudbray, Numel, Staravia, and Torkoal.
|
||||
- Fixed Torkoal's walk speed not matching its animation. He will no longer move faster than Bunnelby and Buneary. This tortoise would've won.
|
||||
- Fixed Lanturn T-posing due to missing ground walk and sleep animations.
|
||||
- Fixed Oshawott and Dewott using their sleep animation in unintended scenarios.
|
||||
- Fixed Dudunsparce and Maushold always having the same form instead of having the 1 in 100 chance of being different.
|
||||
- Fixed bird mounts rapidly switching between their flying and gliding animations when flying at low speed.
|
||||
- Fixed some battles being startable with fainted Pokémon in the initial sendout.
|
||||
- Fixed random gender selection for forms with strict gender divides (such as Meowstic and Oinkologne) never choosing female (that's sexist).
|
||||
- Fixed the "Press R to battle" prompt not disappearing after you finish your first battle, at least until you relogged.
|
||||
- Fixed the composter block being listed as "composer" in the cosmetic items species feature
|
||||
- Fixed Castform's forms being tagged as introduced in generation 4 instead of 3.
|
||||
- Fixed Blitzle's base scale being `1` rather than the intended `0.8`.
|
||||
- Fixed Magnezone's emissive layer for the shiny having the wrong name, thus displaying wrongly.
|
||||
- Fixed Litleo not blinking.
|
||||
|
||||
### Developer
|
||||
- Added `PokeSnackSpawnerFactory` which allows influence registration on PokeSnack encounters.
|
||||
- Added `FishingSpawnerFactory` which allows influence registration on fishing encounters.
|
||||
- Added `BattleFleeAttemptEvent` fired from `PokemonBattle.checkFleeAttempt`, allowing developers to intercept and control flee attempts.
|
||||
- Tweaked the spawning selector interface to take a bucket function rather than a bucket directly.
|
||||
- Added a new `cobblemon:height_range` processor type to allow developers to restrict structure-spawning ranges.
|
||||
- Separated all the functions of MoLangFunctions.kt into their own files.
|
||||
- Spawn buckets and their base weights are now provided by the spawner, with different base weights for world, fishing, snack, and habitat spawn buckets.
|
||||
- Removed "SpawnBucket" class in favour of just storing maps of bucket names to weights.
|
||||
- Fixed nicknames not being applied to Pokémon spawned from `spawn_pool_world` files.
|
||||
- Added support for `profilePokedexScale`, `profilePokedexTranslation`, `profileSummaryScale`, and `profileSummaryTranslation` in poser files for finer control over profile displays.
|
||||
- Fixed riding camera offsets defined on Pokémon forms not being applied.
|
||||
- Marks can now provide aspects.
|
||||
|
||||
### Molang & Datapacks
|
||||
- Added `moveset_builders` datapack folder for different styles of movesets.
|
||||
- Added `party_pools` datapack folder for defining groups of Pokémon for complex NPC party definitions.
|
||||
- Added `party_compositions` datapack folder for arranging parties on NPCs that rely on party pools.
|
||||
- Added `composed_pool` NPC party provider type which combines a party pool with a party composition to create more complex NPC parties.
|
||||
- Added basic chatter NPC Behaviour.
|
||||
- Added `q.item.is_enchanted()`.
|
||||
- Added `q.item.has_enchantment(minecraft:sharpness, 3)`.
|
||||
- Added `has_chosen_starter` and `get_starter_uuid` as available Molang functions.
|
||||
- Added `has_tm_move_unlocked`, `unlock_tm_move`, and `lock_tm_move` as available Molang functions for Players.
|
||||
- Added `marks`, `has_mark`, and `remove_marks` as available Molang functions for Pokémon.
|
||||
- Added Data Component support for species drops, eg `"components": {"minecraft:custom_model_data": 123}`
|
||||
- Added the new `sortOrder` field to mark entries, (defaults to 0 if not specified) which controls the order in which marks are rendered on the HUD, with higher numbers being rendered on top of lower numbers.
|
||||
- Added optional `order` field to starter categories. It will allow explicitly sorting categories in the starter selection screen.
|
||||
- SpeciesAdditions append vs override now matches the wiki documentation.
|
||||
- Added `weighted_choice` as a new feature type. It requires setting weights for each choice and allows developers to simplify the process of assigning random aspect choice based on marble chance.
|
||||
- Added `q.world.spawn_loot_table_items(loot_table_id, x, y, z)` which spawns the items from the loot table at the position. Use type: `minecraft:chest` for the loot table.
|
||||
- Added `q.pokemon.entity` to access the entity of Pokémon.
|
||||
- Flamethrower and Seismic Toss had their action effect JSON cleaned up.
|
||||
- Ride sounds can now be set as exclusive to passengers.
|
||||
- Ride sounds no longer play when submerged unless specified with a new setting.
|
||||
- NPC Trainers can now call a `command` animation when issuing a command in battle.
|
||||
- Added a q.failed function to move action effects.
|
||||
- Herd spawned Pokémon have their levels controlled differently. The `levelRange` property now acts as a pre-offset clamp instead of a filter, with a new `herdLevelRange` property to do the filter behaviour.
|
||||
- `q.sound` now accepts three parameters (sound event, volume, and pitch) instead of just the sound event and pitch.
|
||||
- Added a new layer property that makes a layer scroll in a direction. "scrolling": {"speedU": 0.1, "speedV": 0.1}
|
||||
- Cleaned up seat data. Removed all now unused fields from seats in all species files. Also made locator seat names explicit in the species files (however, this doesn't break the legacy format)
|
||||
|
||||
### Particles
|
||||
|
||||
#### New Move Animations
|
||||
- Blizzard
|
||||
- Disarming Voice
|
||||
- Draco Meteor
|
||||
- Dragon Breath
|
||||
- Dragon Rage
|
||||
- Drain Punch
|
||||
- Fairy Wind
|
||||
- Fire Fang
|
||||
- Gust
|
||||
- Horn Drill
|
||||
- Hydro Pump
|
||||
- Ice Fang
|
||||
- Leafage
|
||||
- Leaf Storm
|
||||
- Light Screen
|
||||
- Night Shade
|
||||
- Play Rough
|
||||
- Pyro Ball
|
||||
- Reflect
|
||||
- Rock Slide
|
||||
- Sonic Boom
|
||||
- Sucker Punch
|
||||
- Supersonic
|
||||
- Thunder Fang
|
||||
|
||||
#### Tweaks and Fixes (Moves)
|
||||
|
||||
- Confusion
|
||||
- Dragon Claw
|
||||
- Eruption
|
||||
- Fire Punch
|
||||
- Flame Burst
|
||||
- Flame Charge
|
||||
- Flamethrower
|
||||
- Frost Breath
|
||||
- Hypnosis
|
||||
- Ice Punch
|
||||
- Icy Wind
|
||||
- Mud Sport
|
||||
- Poison Fang
|
||||
- Protect
|
||||
- Psychic
|
||||
- Quick Attack
|
||||
- Rage Powder
|
||||
- Razor Leaf
|
||||
- Sand Attack
|
||||
- Scratch
|
||||
- Shadow Claw
|
||||
- Sing
|
||||
- Spore
|
||||
- String Shot
|
||||
- Tackle
|
||||
- Tail Whip
|
||||
- Thunder
|
||||
- Thunder Punch
|
||||
- Thunder Wave
|
||||
- Water Gun
|
||||
- Water Pulse
|
||||
- Water Sport
|
||||
|
||||
#### Miscellaneous Particles
|
||||
|
||||
- Added Wild Might particles for Alpha Pokémon.
|
||||
- Updated stat increase and decrease particles.
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- Japanese
|
||||
- German
|
||||
- Spanish
|
||||
- Ecuadorian Spanish
|
||||
- Portuguese
|
||||
- Brazilian Portuguese
|
||||
- Simplified Chinese
|
||||
- Traditional Chinese
|
||||
- Korean
|
||||
- Russian
|
||||
@@ -1,41 +0,0 @@
|
||||
# Changelog
|
||||
## [1.8.1 (September 13th, 2026)](#1-8-1)
|
||||
|
||||
### Animation updates for the following Pokémon
|
||||
- Flapple, Appletun, Dipplin, Hydrapple (placeholder animations only).
|
||||
|
||||
### Fixes
|
||||
- Fixed a potential world generation stall caused by Type Gem clusters.
|
||||
- Fixed Pokémon on shoulders not animating if they are visibly holding a held item.
|
||||
- Fixed NPCs getting their own TM progress file.
|
||||
- Fixed odd NeoForge crash due to a dependency being outdated. It will now correctly flag the dependency for being outdated.
|
||||
- Fixed the TM Machine refusing move selections that the `unlockAllMoveDexMovesByDefault` config had made visible, leaving the move slot blank and the craft button unresponsive.
|
||||
- Fixed the Beast Ball not applying its 0.1× penalty to Pokémon that are not Ultra Beasts.
|
||||
- Fixed the Moon Ball reading the world's total elapsed time instead of the time of day, so its bonus applied during the day instead.
|
||||
- Fixed the Love Ball never awarding its 2.5× opposite gender bonus, and matching species by display name instead of identifier.
|
||||
- Fixed the Timer Ball being weaker than a regular Poké Ball on early turns and only reaching 4× on turn 14 instead of turn 10.
|
||||
- Fixed the Luxury Ball only doubling Friendship gains of 1, leaving level up and berry gains unaffected.
|
||||
- Fixed Rufflet, Braviary, and Hisuian Braviary flooding logs with errors about missing sound events.
|
||||
- Fixed Pokémon property typos in Pangoro and Dedenne herd spawn files.
|
||||
- Fixed unintentional watermelon cosmetic for Hisuian Electrode.
|
||||
- Fixed Blastoise having an unintentional passenger seat.
|
||||
- Fixed form typo in Rockruff-Dusk spawn, preventing it from being able to spawn.
|
||||
- Fixed the `stat_compare` and `stat_equal` evolution requirements crashing the game when given `special_attack` or `special_defence`, and made them treat any non-permanent stat as a failed requirement instead of crashing.
|
||||
- Fixed Rowap and Jacoba berries not correctly altering Pokémon sizes when used as bait.
|
||||
- Fixed Ampharos' eyes not emitting particles.
|
||||
- Fixed Alolan Raticate's cry not playing.
|
||||
- Fixed several incorrect light-based spawning conditions for ghosts and bugs.
|
||||
- Removed unused, placeholder habitat pools.
|
||||
- Fixed Mantyke, Mantine, and Quaxly getting stuck in a recoil 'expression' during battles due to having an expression assigned as a recoil animation.
|
||||
- Fixed Lucario's aura particles not emitting.
|
||||
- Fixed Lycanroc's head movement.
|
||||
- Added head movement to Archaludon.
|
||||
- Fixed Duraludon line not having their sleep animations.
|
||||
- Fixed Diglett line not having their faint animations.
|
||||
- Fixed Kingambit moving its legs while walking.
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- Brazilian Portuguese
|
||||
- Simplified Chinese
|
||||
- Japanese
|
||||
+16
-20
@@ -1,8 +1,9 @@
|
||||
|
||||
import utilities.isSnapshot
|
||||
import utilities.version
|
||||
import utilities.gitBranch
|
||||
import utilities.gitCommit
|
||||
import java.time.OffsetDateTime
|
||||
import java.time.ZoneOffset
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
/*
|
||||
*
|
||||
@@ -31,6 +32,10 @@ repositories {
|
||||
maven(url = "https://api.modrinth.com/maven")
|
||||
maven(url = "https://maven.neoforged.net/releases")
|
||||
maven(url = "https://maven.gegy.dev")
|
||||
exclusiveContent {
|
||||
forRepository { maven(url = "https://maven.isxander.dev/releases") }
|
||||
filter { includeGroup("dev.isxander") }
|
||||
}
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
@@ -54,13 +59,18 @@ dependencies {
|
||||
// modCompileOnly(libs.flywheelFabric)
|
||||
|
||||
// Showdown
|
||||
modCompileOnly(libs.graal.core)
|
||||
modCompileOnly(libs.graal)
|
||||
|
||||
// Data Storage
|
||||
modCompileOnly(libs.bundles.mongo)
|
||||
|
||||
// Unit Testing
|
||||
testImplementation(libs.bundles.unitTesting)
|
||||
|
||||
// Controlify Compat, same as flywheel so we pick one and only use the api
|
||||
modCompileOnlyApi("dev.isxander:controlify:2.4.3+1.21.1-fabric") {
|
||||
isTransitive = false
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<Test> {
|
||||
@@ -71,18 +81,6 @@ tasks.withType<Test> {
|
||||
}
|
||||
}
|
||||
|
||||
// Git info lives in its own output dir (not processResources) so a new commit only rewrites this one file.
|
||||
val writeGitInfo by tasks.registering(WriteProperties::class) {
|
||||
destinationFile = layout.buildDirectory.file("generated/gitInfo/cobblemon-git.properties")
|
||||
property("commit", gitCommit())
|
||||
property("branch", gitBranch())
|
||||
}
|
||||
sourceSets.main { output.dir(mapOf("builtBy" to writeGitInfo), layout.buildDirectory.dir("generated/gitInfo")) }
|
||||
|
||||
tasks.processResources {
|
||||
exclude("data/**/README.md")
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
blossom {
|
||||
@@ -105,13 +103,11 @@ sourceSets {
|
||||
property("modid", "cobblemon")
|
||||
property("version", project.version())
|
||||
property("isSnapshot", if(rootProject.isSnapshot()) "true" else "false")
|
||||
property("gitCommit", versioning.info.commit)
|
||||
property("branch", versioning.info.branch)
|
||||
System.getProperty("buildNumber")?.let { property("buildNumber", it) }
|
||||
property("timestamp", OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ofPattern("MM/dd/yyyy hh:mm:ss")) + " UTC")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The platform jars are built from :common:jar, so the remapped common jars are only needed by `publish`
|
||||
tasks.assemble {
|
||||
setDependsOn(dependsOn.filterNot { (it as? TaskProvider<*>)?.name in setOf("remapJar", "remapSourcesJar") })
|
||||
}
|
||||
|
||||
@@ -13,6 +13,5 @@ public interface ChannelDuck {
|
||||
void cobblemon$inverseAttenuation(float rolloffFactor);
|
||||
void cobblemon$clearFilters();
|
||||
|
||||
void cobblemon$applyReverb(float decayTime, float gain, float diffusion, float density);
|
||||
void cobblemon$clearReverb();
|
||||
// void cobblemon$exponentialAttenuation(float rolloff, float refDistance, float maxDistance);
|
||||
}
|
||||
|
||||
@@ -1,24 +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.resources.ResourceKey;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Duck that facilitates getting a level key for a given level.
|
||||
*
|
||||
* @author dualspiral
|
||||
* @since August 30th, 2026
|
||||
*/
|
||||
public interface MinecraftServerDuck {
|
||||
Optional<ResourceKey<Level>> cobblemon$getLevelKey(Level level);
|
||||
}
|
||||
@@ -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.duck;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
/**
|
||||
* Duck that facilitates getting a level key that we store on the level.
|
||||
*
|
||||
* @author dualspiral
|
||||
* @since August 30th, 2026
|
||||
*/
|
||||
public interface ServerLevelDuck {
|
||||
ResourceLocation cobblemon$getLevelResourceLocation();
|
||||
}
|
||||
@@ -11,9 +11,7 @@ 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.api.pokemon.PokemonProperties;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.world.feature.SaccharineTreeFeature;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
@@ -44,21 +42,7 @@ public abstract class BeeOccupantMixin {
|
||||
if (cir.getReturnValue() == null) {
|
||||
final BeehiveBlockEntity.Occupant occupant = (BeehiveBlockEntity.Occupant) (Object) this;
|
||||
CompoundTag compoundTag = occupant.entityData().copyTag();
|
||||
String id = compoundTag.getString("id");
|
||||
Entity entity = null;
|
||||
if (id.equals(SaccharineTreeFeature.Companion.getPOKEMON_PLACEHOLD_ID())) {
|
||||
// Special case for Pokemon stuffed into a beenest upon world gen.
|
||||
// For technical reasons we cannot create them as full entities during world gen.
|
||||
// So we look for this special id tag and complete the entity when it attempts to exit a hive.
|
||||
if (compoundTag.contains("pokemonProperties")) {
|
||||
String properties = compoundTag.getString("pokemonProperties");
|
||||
PokemonProperties pokemon = PokemonProperties.Companion.parse(properties);
|
||||
entity = pokemon.createEntity(level);
|
||||
}
|
||||
} else {
|
||||
entity = EntityType.loadEntityRecursive(compoundTag, level, (entityx) -> entityx);
|
||||
}
|
||||
|
||||
Entity entity = EntityType.loadEntityRecursive(compoundTag, level, (entityx) -> entityx);
|
||||
if (entity instanceof PokemonEntity pokemonEntity) {
|
||||
var state = level.getBlockState(pos);
|
||||
var newPos = Vec3.ZERO;
|
||||
@@ -67,14 +51,14 @@ public abstract class BeeOccupantMixin {
|
||||
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).getBottomCenter();
|
||||
newPos = pos.relative(facing).getCenter();
|
||||
newYaw = facing.toYRot();
|
||||
if (brain.checkMemory(CobblemonMemories.HIVE_LOCATION, MemoryStatus.REGISTERED)) {
|
||||
brain.setMemory(CobblemonMemories.HIVE_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.getBottomCenter();
|
||||
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,
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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,36 +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.CobblemonItemComponents;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.ItemModelShaper;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
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(ItemModelShaper.class)
|
||||
public class ItemModelShaperMixin {
|
||||
|
||||
@Inject(method = "getItemModel(Lnet/minecraft/world/item/ItemStack;)Lnet/minecraft/client/resources/model/BakedModel;", at = @At("HEAD"), cancellable = true)
|
||||
public void getItemModel(ItemStack stack, CallbackInfoReturnable<BakedModel> cir) {
|
||||
String eggModel = stack.get(CobblemonItemComponents.EGG_MODEL);
|
||||
if (eggModel == null) return;
|
||||
|
||||
ModelResourceLocation modelResourceLocation = ModelResourceLocation.inventory(ResourceLocation.parse("cobblemon:egg/" + eggModel));
|
||||
BakedModel bakedModel = Minecraft.getInstance().getModelManager().getModel(modelResourceLocation);
|
||||
cir.setReturnValue(bakedModel);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
import com.cobblemon.mod.common.duck.MinecraftServerDuck;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
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 java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@Mixin(MinecraftServer.class)
|
||||
public class MinecraftServerMixin implements MinecraftServerDuck {
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private Map<ResourceKey<Level>, ServerLevel> levels;
|
||||
|
||||
@Override
|
||||
public Optional<ResourceKey<Level>> cobblemon$getLevelKey(final Level level) {
|
||||
return this.levels.entrySet()
|
||||
.stream()
|
||||
// Reference equality is intended here, the level we're handed is the same one as in the
|
||||
// map so we don't need to check value semantics.
|
||||
.filter(entry -> entry.getValue() == level)
|
||||
.map(Map.Entry::getKey)
|
||||
.findFirst();
|
||||
}
|
||||
}
|
||||
@@ -1,55 +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.client.color.block.BlockColors;
|
||||
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||
import net.minecraft.client.resources.model.BlockStateModelLoader;
|
||||
import net.minecraft.client.resources.model.ModelBakery;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(ModelBakery.class)
|
||||
public abstract class ModelBakeryMixin {
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private Map<ResourceLocation, BlockModel> modelResources;
|
||||
|
||||
@Shadow
|
||||
protected abstract void loadItemModelAndDependencies(ResourceLocation modelLocation);
|
||||
|
||||
@Inject(method = "<init>", at = @At("TAIL"))
|
||||
private void cobblemon$loadEggModels(
|
||||
BlockColors blockColors,
|
||||
ProfilerFiller profilerFiller,
|
||||
Map<ResourceLocation, BlockModel> modelResources,
|
||||
Map<ResourceLocation, List<BlockStateModelLoader.LoadedJson>> blockStateResources,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
for (ResourceLocation fileLocation : this.modelResources.keySet()) {
|
||||
if (!fileLocation.getNamespace().equals("cobblemon")) continue;
|
||||
String path = fileLocation.getPath();
|
||||
|
||||
if (!path.startsWith("models/item/egg/")) continue;
|
||||
String modelPath = path.replace("models/item/", "").replace(".json", "");
|
||||
ResourceLocation modelId = new ResourceLocation("cobblemon", modelPath);
|
||||
this.loadItemModelAndDependencies(modelId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.block.entity.DiscShelfBlockEntity;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.NoteBlock;
|
||||
import net.minecraft.world.level.block.state.properties.NoteBlockInstrument;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(NoteBlock.class)
|
||||
public abstract class NoteBlockMixin {
|
||||
@Inject(method = "triggerEvent", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$triggerTMShelfSequencer(BlockState state, Level level, BlockPos pos, int type, int data, CallbackInfoReturnable<Boolean> cir) {
|
||||
final BlockPos shelfPos = pos.below();
|
||||
final BlockEntity blockEntity = level.getBlockEntity(shelfPos);
|
||||
if (!(blockEntity instanceof DiscShelfBlockEntity discShelfBlockEntity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!level.isClientSide) {
|
||||
final BlockPos instrumentPos = shelfPos.below();
|
||||
final SoundEvent soundEvent;
|
||||
if (level.getBlockState(instrumentPos).isAir()) {
|
||||
soundEvent = SoundEvents.NOTE_BLOCK_BIT.value();
|
||||
} else {
|
||||
final NoteBlockInstrument instrument = level.getBlockState(instrumentPos).instrument();
|
||||
final Holder<SoundEvent> holder = instrument.getSoundEvent();
|
||||
soundEvent = holder.value();
|
||||
}
|
||||
discShelfBlockEntity.onNoteBlockPulse(level, pos, soundEvent);
|
||||
}
|
||||
|
||||
// Suppress vanilla note-block playback while it is on top of a TM Shelf.
|
||||
cir.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,6 @@ 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.riding.RidingStyle;
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.air.HoverBehaviour;
|
||||
import com.cobblemon.mod.common.api.storage.party.PartyStore;
|
||||
import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore;
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
|
||||
@@ -61,7 +59,6 @@ import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@@ -172,32 +169,6 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
method = "getDestroySpeed",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/entity/player/Player;onGround()Z"
|
||||
)
|
||||
)
|
||||
private boolean cobblemon$considerHoverOnGround(Player player) {
|
||||
// If riding a Hover Mount, return true to bypass the 5x slowdown
|
||||
if (player.getVehicle() instanceof PokemonEntity vehicle) {
|
||||
|
||||
var ridingController = vehicle.getRidingController();
|
||||
if (ridingController == null) player.onGround();
|
||||
|
||||
var activeContext = ridingController.getContext();
|
||||
if (activeContext == null) player.onGround();
|
||||
|
||||
if (activeContext.getStyle() == RidingStyle.AIR &&
|
||||
activeContext.getBehaviour().equals(HoverBehaviour.Companion.getKEY())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Otherwise, return the actual value
|
||||
return player.onGround();
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "eat",
|
||||
at = @At(
|
||||
|
||||
@@ -19,10 +19,8 @@ import com.cobblemon.mod.common.mixin.accessor.TrackedEntityAccessor;
|
||||
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateDriverInputPacket;
|
||||
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateOrientationPacket;
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.ClientboundUpdateRidingStatePacket;
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.ClientboundSeatAssignmentPacket;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.ServerEntity;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
@@ -39,8 +37,6 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -57,15 +53,12 @@ public abstract class ServerEntityMixin {
|
||||
private Matrix3f cobblemon$lastSentOrientation;
|
||||
@Unique
|
||||
private boolean cobblemon$lastSentActive;
|
||||
@Unique
|
||||
private List<Entity> cobblemon$lastSeatPassengers = List.of();
|
||||
|
||||
@Inject(method = "sendChanges", at = @At("TAIL"))
|
||||
private void cobblemon$sendChanges(CallbackInfo ci) {
|
||||
cobblemon$sendOrientationChanges();
|
||||
cobblemon$sendRidingStateChanges();
|
||||
cobblemon$sendDriverInput();
|
||||
cobblemon$sendOccupiedSeatsChange();
|
||||
}
|
||||
|
||||
private void cobblemon$sendRidingStateChanges() {
|
||||
@@ -108,22 +101,6 @@ public abstract class ServerEntityMixin {
|
||||
cobblemon$broadcast(new ClientboundUpdateDriverInputPacket(driverInput, entity.getId()));
|
||||
}
|
||||
|
||||
private void cobblemon$sendOccupiedSeatsChange() {
|
||||
if (!(this.entity instanceof PokemonEntity pokemon)) return;
|
||||
|
||||
List<Entity> currentPassengers = pokemon.getPassengers();
|
||||
if (currentPassengers.equals(cobblemon$lastSeatPassengers)) return;
|
||||
cobblemon$lastSeatPassengers = List.copyOf(currentPassengers);
|
||||
|
||||
var assignments = new LinkedHashMap<String, Integer>();
|
||||
pokemon.getOccupiedSeats().forEach((seat, passenger) -> {
|
||||
if (seat.getLocator() == null) return;
|
||||
if (passenger == null) return;
|
||||
assignments.put(seat.getLocator(), passenger.getId());
|
||||
});
|
||||
cobblemon$broadcast(new ClientboundSeatAssignmentPacket(pokemon.getId(), assignments));
|
||||
}
|
||||
|
||||
private void cobblemon$broadcast(NetworkPacket<?> packet) {
|
||||
if (!(entity.level() instanceof ServerLevel level)) return;
|
||||
ChunkMap chunkMap = level.getChunkSource().chunkMap;
|
||||
@@ -138,4 +115,5 @@ public abstract class ServerEntityMixin {
|
||||
CobblemonNetwork.INSTANCE.sendPacketToPlayer(player, packet);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,69 +8,22 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.duck.MinecraftServerDuck;
|
||||
import com.cobblemon.mod.common.duck.ServerLevelDuck;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
import net.minecraft.world.level.storage.WritableLevelData;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
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;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
|
||||
@Mixin(ServerLevel.class)
|
||||
public abstract class ServerLevelMixin extends Level implements ServerLevelDuck {
|
||||
|
||||
// Ignored by Mixin, fulfils Java contract
|
||||
protected ServerLevelMixin(
|
||||
WritableLevelData levelData,
|
||||
ResourceKey<Level> dimension,
|
||||
RegistryAccess registryAccess,
|
||||
Holder<DimensionType> dimensionTypeRegistration,
|
||||
Supplier<ProfilerFiller> profiler,
|
||||
boolean isClientSide,
|
||||
boolean isDebug,
|
||||
long biomeZoomSeed,
|
||||
int maxChainedNeighborUpdates
|
||||
) {
|
||||
super(levelData, dimension, registryAccess, dimensionTypeRegistration, profiler, isClientSide, isDebug, biomeZoomSeed, maxChainedNeighborUpdates);
|
||||
}
|
||||
|
||||
@Shadow
|
||||
public abstract MinecraftServer shadow$getServer();
|
||||
|
||||
/**
|
||||
* Cached to speed up level world key checks every tick.
|
||||
*/
|
||||
private ResourceLocation cobblemon$levelResourceLocation;
|
||||
|
||||
@Override
|
||||
public ResourceLocation cobblemon$getLevelResourceLocation() {
|
||||
if (this.cobblemon$levelResourceLocation == null) {
|
||||
this.cobblemon$levelResourceLocation = ((MinecraftServerDuck) this.shadow$getServer())
|
||||
.cobblemon$getLevelKey(this)
|
||||
.map(ResourceKey::location)
|
||||
.orElse(null);
|
||||
}
|
||||
return this.cobblemon$levelResourceLocation;
|
||||
}
|
||||
public abstract class ServerLevelMixin {
|
||||
|
||||
@Inject(method = "findLightningRod", at = @At(value = "RETURN"), cancellable = true)
|
||||
private void cobblemon$findLightningRod(BlockPos blockPos, CallbackInfoReturnable<Optional<BlockPos>> ci) {
|
||||
|
||||
@@ -15,18 +15,15 @@ import com.cobblemon.mod.common.api.riding.RidingStyle;
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner;
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory;
|
||||
import com.cobblemon.mod.common.api.stats.CobblemonStats;
|
||||
import com.cobblemon.mod.common.duck.ServerLevelDuck;
|
||||
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.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
@@ -36,13 +33,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ServerPlayer.class)
|
||||
public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
|
||||
|
||||
@Shadow
|
||||
public abstract ServerLevel serverLevel();
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
public MinecraftServer server;
|
||||
@Unique
|
||||
public PlayerSpawner cobblemon$spawner;
|
||||
|
||||
@@ -62,9 +55,12 @@ public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
|
||||
|
||||
@Inject(method = "tick", at = @At("TAIL"))
|
||||
private void cobblemon$tickSpawner(CallbackInfo ci) {
|
||||
if (cobblemon$canSpawn()) {
|
||||
getPlayerSpawner().tick();
|
||||
if (!Cobblemon.config.getEnableSpawning()) {
|
||||
return;
|
||||
} else if (!serverLevel().getGameRules().getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING)) {
|
||||
return;
|
||||
}
|
||||
getPlayerSpawner().tick();
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
@@ -125,21 +121,4 @@ public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether we should spawn Cobblemon entities here.
|
||||
*
|
||||
* @return true if we can spawn cobblemon in the current level,
|
||||
* false otherwise
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
@Unique
|
||||
private boolean cobblemon$canSpawn() {
|
||||
return Cobblemon.config.getEnableSpawning() &&
|
||||
this.serverLevel().getGameRules().getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING) &&
|
||||
// intentionally last as this is a more expensive check, even with all the caching
|
||||
!Cobblemon.config.getWorldSpawningBlocklist().contains(
|
||||
((ServerLevelDuck) this.serverLevel()).cobblemon$getLevelResourceLocation()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ 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.util.Mth;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
@@ -33,7 +32,6 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
import java.util.Iterator;
|
||||
@@ -110,17 +108,6 @@ public abstract class SoundEngineMixin implements SoundEngineDuck {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TM Shelf can intentionally push note-block pitches above vanilla's 2.0f ceiling for octave-up playback.
|
||||
* Keep vanilla clamping for all other sounds.
|
||||
*/
|
||||
@Inject(method = "calculatePitch", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$allowExtendedNoteblockPitch(SoundInstance sound, CallbackInfoReturnable<Float> cir) {
|
||||
if (sound.getLocation().getPath().startsWith("block.note_block.")) {
|
||||
cir.setReturnValue(Mth.clamp(sound.getPitch(), 0.5F, 4.0F));
|
||||
}
|
||||
}
|
||||
|
||||
/** Different behavior for resuming SoundInstances while a BattleMusicInstance is being played. We do not want to resume filtered sounds. */
|
||||
@Inject(method = "resume()V", at = @At("HEAD"), cancellable = true)
|
||||
public void resume(CallbackInfo cb) {
|
||||
|
||||
@@ -8,25 +8,21 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.mixin.accessor.SinglePoolElementAccessor;
|
||||
import com.cobblemon.mod.common.world.structureprocessors.HeightRangeStructureProcessor;
|
||||
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.PoolElementStructurePiece;
|
||||
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.pools.SinglePoolElement;
|
||||
import net.minecraft.world.level.levelgen.structure.pools.StructurePoolElement;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessor;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorList;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
@@ -34,70 +30,38 @@ 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.Optional;
|
||||
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
|
||||
));
|
||||
|
||||
/**
|
||||
* Discards a structure start when any of its pieces carries a {@link HeightRangeStructureProcessor}
|
||||
* whose range the piece does not fit in.
|
||||
* Crab Note: We have to make this has to happen here rather than in the processor itself. Terrain adaptation and {@code /locate}
|
||||
* both read the start, so by the time processors run the terrain has already been generated and the
|
||||
* structure is already on the map which previously were left behdind when we were trying to make some structures not generate via processor. Now
|
||||
* Returning {@link StructureStart#INVALID_START} keeps the start from ever existing, which makes sure that weird generation isn't left behind.
|
||||
*/
|
||||
@Inject(
|
||||
method = "generate",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/levelgen/structure/StructureStart;isValid()Z"),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$rejectStartsOutsideHeightRange(
|
||||
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
|
||||
) {
|
||||
for (StructurePiece piece : structureStart.getPieces()) {
|
||||
if (!(piece instanceof PoolElementStructurePiece poolPiece)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Optional<HeightRangeStructureProcessor> heightRangeProcessor = cobblemon$getHeightRangeProcessor(poolPiece.getElement());
|
||||
if (heightRangeProcessor.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean valid = heightRangeProcessor.get().isValidPlacement(
|
||||
chunkGenerator,
|
||||
heightAccessor,
|
||||
randomState,
|
||||
piece.getBoundingBox()
|
||||
);
|
||||
|
||||
if (!valid) {
|
||||
cir.setReturnValue(StructureStart.INVALID_START);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static Optional<HeightRangeStructureProcessor> cobblemon$getHeightRangeProcessor(StructurePoolElement element) {
|
||||
if (!(element instanceof SinglePoolElement)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
StructureProcessorList processorList = ((SinglePoolElementAccessor) element).getProcessors().value();
|
||||
for (StructureProcessor processor : processorList.list()) {
|
||||
if (processor instanceof HeightRangeStructureProcessor heightRangeStructureProcessor) {
|
||||
return Optional.of(heightRangeStructureProcessor);
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.core.dispenser.DispenseItemBehavior;
|
||||
import net.minecraft.world.level.block.DispenserBlock;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(DispenserBlock.class)
|
||||
public interface DispenserBlockAccessor {
|
||||
@Accessor("DISPENSER_REGISTRY")
|
||||
static Map<Item, DispenseItemBehavior> getItemBehaviors() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
-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.core.Holder;
|
||||
import net.minecraft.world.level.levelgen.structure.pools.SinglePoolElement;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorList;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(SinglePoolElement.class)
|
||||
public interface SinglePoolElementAccessor {
|
||||
@Accessor("processors")
|
||||
Holder<StructureProcessorList> getProcessors();
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.client.CobblemonClient;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(Minecraft.class)
|
||||
public class AIDebugGlowMixin {
|
||||
|
||||
@Inject(method = "shouldEntityAppearGlowing", at = @At("HEAD"), cancellable = true)
|
||||
public void cobblemon$debugEntityGlow(Entity entity, CallbackInfoReturnable<Boolean> cir) {
|
||||
if (entity.getId() == CobblemonClient.INSTANCE.getDebuggedEntityId()) {
|
||||
cir.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.duck.ChannelDuck;
|
||||
import com.mojang.blaze3d.audio.Channel;
|
||||
import org.lwjgl.openal.AL10;
|
||||
import org.lwjgl.openal.AL11;
|
||||
import org.lwjgl.openal.EXTEfx;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
@Mixin(Channel.class)
|
||||
public abstract class ChannelMixin implements ChannelDuck {
|
||||
|
||||
@Shadow
|
||||
private int source;
|
||||
|
||||
// Ids of effects applied to the channel
|
||||
private int cobblemon$lowPassFilterId = 0;
|
||||
private int cobblemon$reverbEffectId = 0;
|
||||
private int cobblemon$reverbSlotId = 0;
|
||||
|
||||
@Override
|
||||
public void cobblemon$applyLowPassFilter(float gain, float hfGain) {
|
||||
// Delete old filter if it exists
|
||||
if (cobblemon$lowPassFilterId != 0) {
|
||||
AL10.alSourcei(source, EXTEfx.AL_DIRECT_FILTER, 0); // Detach filter from source
|
||||
EXTEfx.alDeleteFilters(cobblemon$lowPassFilterId); // Delete old filter
|
||||
cobblemon$lowPassFilterId = 0;
|
||||
}
|
||||
|
||||
// Generate a fresh filter
|
||||
int filterId = EXTEfx.alGenFilters();
|
||||
if (!EXTEfx.alIsFilter(filterId)) {
|
||||
System.err.println("Failed to create OpenAL low-pass filter");
|
||||
return;
|
||||
}
|
||||
|
||||
EXTEfx.alFilteri(filterId, EXTEfx.AL_FILTER_TYPE, EXTEfx.AL_FILTER_LOWPASS);
|
||||
EXTEfx.alFilterf(filterId, EXTEfx.AL_LOWPASS_GAIN, gain);
|
||||
EXTEfx.alFilterf(filterId, EXTEfx.AL_LOWPASS_GAINHF, hfGain);
|
||||
|
||||
AL10.alSourcei(source, EXTEfx.AL_DIRECT_FILTER, filterId);
|
||||
|
||||
// Save the new filter ID
|
||||
cobblemon$lowPassFilterId = filterId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$inverseAttenuation(float rolloffFactor) {
|
||||
AL10.alSourcei(source, AL10.AL_DISTANCE_MODEL, AL10.AL_INVERSE_DISTANCE);
|
||||
AL10.alSourcef(source, AL10.AL_ROLLOFF_FACTOR, rolloffFactor);
|
||||
AL10.alSourcef(source, AL10.AL_REFERENCE_DISTANCE, 1.0f);
|
||||
AL10.alSourcef(source, AL10.AL_MAX_DISTANCE, 0.0f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$clearFilters() {
|
||||
AL10.alSourcei(source, EXTEfx.AL_DIRECT_FILTER, 0);
|
||||
|
||||
if (EXTEfx.alIsFilter(cobblemon$lowPassFilterId)) {
|
||||
EXTEfx.alDeleteFilters(cobblemon$lowPassFilterId);
|
||||
cobblemon$lowPassFilterId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$applyReverb(float decayTime, float gain, float diffusion, float density) {
|
||||
// Clean up existing reverb first if it exists
|
||||
cobblemon$clearReverb();
|
||||
|
||||
// Create the effect object
|
||||
int effectId = EXTEfx.alGenEffects();
|
||||
if (!EXTEfx.alIsEffect(effectId)) {
|
||||
System.err.println("Failed to create OpenAL reverb effect");
|
||||
return;
|
||||
}
|
||||
|
||||
EXTEfx.alEffecti(effectId, EXTEfx.AL_EFFECT_TYPE, EXTEfx.AL_EFFECT_REVERB);
|
||||
EXTEfx.alEffectf(effectId, EXTEfx.AL_REVERB_DECAY_TIME, decayTime);
|
||||
EXTEfx.alEffectf(effectId, EXTEfx.AL_REVERB_GAIN, gain);
|
||||
EXTEfx.alEffectf(effectId, EXTEfx.AL_REVERB_DIFFUSION, diffusion);
|
||||
EXTEfx.alEffectf(effectId, EXTEfx.AL_REVERB_DENSITY, density);
|
||||
|
||||
// Create auxiliary effect slot and load effect into it
|
||||
int slotId = EXTEfx.alGenAuxiliaryEffectSlots();
|
||||
if (!EXTEfx.alIsAuxiliaryEffectSlot(slotId)) {
|
||||
System.err.println("Failed to create OpenAL auxiliary effect slot");
|
||||
EXTEfx.alDeleteEffects(effectId);
|
||||
return;
|
||||
}
|
||||
|
||||
EXTEfx.alAuxiliaryEffectSloti(slotId, EXTEfx.AL_EFFECTSLOT_EFFECT, effectId);
|
||||
|
||||
// Route source through the slot — send 0, no direct filter
|
||||
AL11.alSource3i(source, EXTEfx.AL_AUXILIARY_SEND_FILTER, slotId, 0, EXTEfx.AL_FILTER_NULL);
|
||||
|
||||
cobblemon$reverbEffectId = effectId;
|
||||
cobblemon$reverbSlotId = slotId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$clearReverb() {
|
||||
if (cobblemon$reverbSlotId != 0) {
|
||||
// Detach source from slot
|
||||
AL11.alSource3i(source, EXTEfx.AL_AUXILIARY_SEND_FILTER,
|
||||
EXTEfx.AL_EFFECTSLOT_NULL, 0, EXTEfx.AL_FILTER_NULL);
|
||||
EXTEfx.alDeleteAuxiliaryEffectSlots(cobblemon$reverbSlotId);
|
||||
cobblemon$reverbSlotId = 0;
|
||||
}
|
||||
if (cobblemon$reverbEffectId != 0) {
|
||||
EXTEfx.alDeleteEffects(cobblemon$reverbEffectId);
|
||||
cobblemon$reverbEffectId = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,15 +9,10 @@
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.CobblemonItemComponents;
|
||||
import com.cobblemon.mod.common.CobblemonItems;
|
||||
import com.cobblemon.mod.common.ModAPI;
|
||||
import com.cobblemon.mod.common.api.breeding.EggTextures;
|
||||
import com.cobblemon.mod.common.item.PokeBallItem;
|
||||
import com.cobblemon.mod.common.item.PokedexItem;
|
||||
import com.cobblemon.mod.common.item.WearableItem;
|
||||
import com.cobblemon.mod.common.item.components.EggComponent;
|
||||
import com.cobblemon.mod.common.item.components.TMMoveComponent;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.ItemModelShaper;
|
||||
@@ -58,29 +53,14 @@ public abstract class ItemRendererMixin {
|
||||
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) throws Exception {
|
||||
boolean shouldBe2d = renderMode == ItemDisplayContext.GUI || renderMode == ItemDisplayContext.FIXED || stack.getItem() == CobblemonItems.POKEMON_EGG || stack.getItem() == CobblemonItems.TECHNICAL_MACHINE;
|
||||
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();
|
||||
} else if (stack.getItem() == CobblemonItems.POKEMON_EGG) {
|
||||
EggComponent component = stack.get(CobblemonItemComponents.EGG_DATA);
|
||||
if (component != null) {
|
||||
resourceLocation = EggTextures.getEggTexture(component.getIdentifier(), component.getVariant());
|
||||
}
|
||||
} else if (stack.getItem() == CobblemonItems.TECHNICAL_MACHINE) {
|
||||
TMMoveComponent component = stack.get(CobblemonItemComponents.TM_MOVE);
|
||||
if (component != null) {
|
||||
resourceLocation = new ResourceLocation(Cobblemon.MODID, "tm/" + component.getMove().getElementalType().showdownId() + "_tm");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (renderMode != ItemDisplayContext.HEAD && stack.getItem() instanceof WearableItem wearableItem) {
|
||||
resourceLocation = wearableItem.getModel2d();
|
||||
if (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"));
|
||||
|
||||
@@ -23,7 +23,6 @@ import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket;
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket;
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdatePassengerPositionPacket;
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateRiderRotationPacket;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.client.CameraType;
|
||||
@@ -149,22 +148,10 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
cobblemon$lastRideYRot = rideYRot;
|
||||
cobblemon$lastRideEyePos = rideEyePos;
|
||||
|
||||
CobblemonNetwork.INSTANCE.sendToServer(
|
||||
new ServerboundUpdateRiderRotationPacket(rideXRot, rideYRot, rideEyePos)
|
||||
);
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateRiderRotationPacket(rideXRot, rideYRot, rideEyePos));
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("TAIL"))
|
||||
private void cobblemon$updatePassengerPosition(CallbackInfo ci) {
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
if (!(this.getVehicle() instanceof PokemonEntity pokemonEntity)) return;
|
||||
if (pokemonEntity.getSeatForPassenger(this) == null) return;
|
||||
|
||||
var offset = this.position().subtract(pokemonEntity.position());
|
||||
CobblemonNetwork.INSTANCE.sendToServer(
|
||||
new ServerboundUpdatePassengerPositionPacket(this.getId(), offset)
|
||||
);
|
||||
}
|
||||
|
||||
@Unique
|
||||
@@ -230,10 +217,9 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
private void cobblemon$isHandsBusy(CallbackInfoReturnable<Boolean> cir) {
|
||||
Entity vehicle = this.getVehicle();
|
||||
if (vehicle instanceof PokemonEntity pokemonEntity) {
|
||||
Seat seat = pokemonEntity.getSeatForPassenger(this);;
|
||||
if (seat != null) {
|
||||
cir.setReturnValue(seat.getHandsBusy());
|
||||
}
|
||||
int seatIndex = pokemonEntity.getPassengers().indexOf(this);
|
||||
Seat seat = pokemonEntity.getSeats().get(seatIndex);
|
||||
cir.setReturnValue(seat.getHandsBusy());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.client.CobblemonBakingOverrides;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import net.minecraft.client.color.block.BlockColors;
|
||||
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||
import net.minecraft.client.resources.model.BlockStateModelLoader;
|
||||
@@ -17,76 +18,29 @@ import net.minecraft.client.resources.model.ModelBakery;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.client.resources.model.UnbakedModel;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.packs.resources.Resource;
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(ModelBakery.class)
|
||||
public abstract class ModelLoaderMixin {
|
||||
|
||||
@Shadow abstract UnbakedModel getModel(ResourceLocation resourceLocation);
|
||||
|
||||
@Shadow protected abstract void registerModel(ModelResourceLocation modelId, UnbakedModel unbakedModel);
|
||||
|
||||
@Shadow protected abstract void loadItemModelAndDependencies(ResourceLocation resourceLocation);
|
||||
|
||||
@Unique
|
||||
List<String> dynamicFolders = Arrays.asList("egg", "tm");
|
||||
|
||||
@Inject(
|
||||
method = "<init>",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/util/profiling/ProfilerFiller;popPush(Ljava/lang/String;)V",
|
||||
ordinal = 1
|
||||
)
|
||||
)
|
||||
public void loadCustomItemModels(BlockColors blockColors,
|
||||
ProfilerFiller profiler,
|
||||
Map<ResourceLocation, BlockModel> jsonUnbakedModels,
|
||||
Map<ResourceLocation, List<BlockStateModelLoader.LoadedJson>> blockStates,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
/*
|
||||
* The models/item/*.json's only get loaded if there's an item in the registry that actually asks for it. It
|
||||
* naively looks for things in the root with an item ID and calls upon it, and some of those JSONs reference
|
||||
* other model JSONs and so it cascades a little bit. Used for block models but more importantly here, sprites.
|
||||
*
|
||||
* The thing about the eggs (and TMs) is, we really want the eggs to be addon-compatible in a way that doesn't restrict
|
||||
* the species that can have eggs, so we can't pre-plan all of them. This mixin looks for the things inside the
|
||||
* egg subfolder (which won't get loaded automagically) and manually inserts them into the unbaked model list so
|
||||
* Minecraft loads them for us. We'll then dynamically call these models from the ItemRendererMixin; so it's
|
||||
* hacky at the init stage and hacky at the render stage. Pretty cool in the gameplay stage though.
|
||||
*
|
||||
* - Hiro
|
||||
*/
|
||||
|
||||
dynamicFolders.forEach(folder -> {
|
||||
Map<ResourceLocation, Resource> map = Minecraft.getInstance().getResourceManager().listResources("models/item/" + folder, (t) -> true);
|
||||
map.forEach((key, value) -> {
|
||||
ResourceLocation resourceLocation = new ResourceLocation(key.getNamespace(), key.getPath().replace("models/item/", "").replace(".json", ""));
|
||||
this.loadItemModelAndDependencies(resourceLocation);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "<init>",
|
||||
at = @At("TAIL")
|
||||
method = "<init>",
|
||||
at = @At("TAIL")
|
||||
)
|
||||
public void init(BlockColors blockColors,
|
||||
ProfilerFiller profiler,
|
||||
Map<ResourceLocation, BlockModel> jsonUnbakedModels,
|
||||
Map<ResourceLocation, List<BlockStateModelLoader.LoadedJson>> blockStates,
|
||||
CallbackInfo ci) {
|
||||
ProfilerFiller profiler,
|
||||
Map<ResourceLocation, BlockModel> jsonUnbakedModels,
|
||||
Map<ResourceLocation, List<BlockStateModelLoader.LoadedJson>> blockStates,
|
||||
CallbackInfo ci) {
|
||||
CobblemonBakingOverrides.INSTANCE.getModels().forEach(bakingOverride -> {
|
||||
var unbakedModel = this.getModel(bakingOverride.getModelLocation());
|
||||
this.registerModel(bakingOverride.getModelIdentifier(), unbakedModel);
|
||||
|
||||
@@ -21,12 +21,14 @@ import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import com.mojang.blaze3d.Blaze3D;
|
||||
import kotlin.Pair;
|
||||
import kotlin.jvm.functions.Function4;
|
||||
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.joml.Vector2d;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
@@ -35,7 +37,6 @@ import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import com.cobblemon.mod.common.client.gui.party.PartyTutorialToasts;
|
||||
|
||||
import static com.google.common.primitives.Floats.min;
|
||||
import static net.minecraft.util.Mth.lerp;
|
||||
@@ -86,13 +87,11 @@ public abstract class MouseHandlerMixin {
|
||||
CobblemonClient.INSTANCE.getStorage().shiftSelected(false);
|
||||
ci.cancel();
|
||||
PartySendBinding.INSTANCE.actioned();
|
||||
PartyTutorialToasts.INSTANCE.onHoldKeyScrollSwitchedSlot();
|
||||
} else if (i < 0) {
|
||||
accumulatedScrollY -= i;
|
||||
CobblemonClient.INSTANCE.getStorage().shiftSelected(true);
|
||||
ci.cancel();
|
||||
PartySendBinding.INSTANCE.actioned();
|
||||
PartyTutorialToasts.INSTANCE.onHoldKeyScrollSwitchedSlot();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,6 +148,12 @@ public abstract class MouseHandlerMixin {
|
||||
pokeVehicle.clampPassengerRotation(player);
|
||||
}
|
||||
|
||||
for(Function4<LocalPlayer, Double, Double, Double, Vector2d> rideFun : CobblemonClient.INSTANCE.getRidingTurnInputHandler().values()) {
|
||||
Vector2d vec = rideFun.invoke(player, cursorDeltaX, cursorDeltaY, d);
|
||||
cursorDeltaX = vec.x;
|
||||
cursorDeltaY = vec.y;
|
||||
}
|
||||
|
||||
// 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();
|
||||
@@ -313,7 +318,7 @@ public abstract class MouseHandlerMixin {
|
||||
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(), -89.0F, 89.0F));
|
||||
playerRotater.cobblemon$setRideXRot(Mth.clamp(playerRotater.cobblemon$getRideXRot(), -90.0F, 90.0F));
|
||||
playerRotater.cobblemon$setRideYRot(Mth.clamp(playerRotater.cobblemon$getRideYRot(), -105.0F, 105.0F));
|
||||
if (player.getVehicle() != null) {
|
||||
player.getVehicle().onPassengerTurned(player);
|
||||
|
||||
@@ -14,14 +14,9 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import com.llamalad7.mixinextras.sugar.Share;
|
||||
import com.llamalad7.mixinextras.sugar.ref.LocalBooleanRef;
|
||||
import com.llamalad7.mixinextras.sugar.ref.LocalFloatRef;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
@@ -94,61 +89,4 @@ public abstract class EntityMixin {
|
||||
cir.setReturnValue(customEyePos);
|
||||
}
|
||||
|
||||
|
||||
@WrapOperation(
|
||||
method = "push(Lnet/minecraft/world/entity/Entity;)V",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;push(DDD)V", ordinal = 0)
|
||||
)
|
||||
public void cobblemon$customPusherLogic(Entity pusher, double x, double y, double z,
|
||||
Operation<Void> original,
|
||||
@Local(argsOnly = true) Entity pushee,
|
||||
@Local(name = "e") double e, @Local(name = "d") double d,
|
||||
@Share("pusherIsPlayerOrPokemon") LocalBooleanRef pusherIsPlayerOrPokemon,
|
||||
@Share("pusheeIsPlayerOrPokemon") LocalBooleanRef pusheeIsPlayerOrPokemon,
|
||||
@Share("pusheeReceivedForce")LocalFloatRef pusheeReceivedForce) {
|
||||
pusherIsPlayerOrPokemon.set(pusher instanceof PokemonEntity || pusher instanceof Player);
|
||||
pusheeIsPlayerOrPokemon.set(pushee instanceof PokemonEntity || pushee instanceof Player);
|
||||
|
||||
if (!pusheeIsPlayerOrPokemon.get() || !pusherIsPlayerOrPokemon.get()) {
|
||||
original.call(pusher, x, y, z);
|
||||
return;
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
* Custom portion of the code:
|
||||
* Handle collisions with weight in mind. Use
|
||||
* the weight value of pokemon to determine
|
||||
* which side gets what portion of the total
|
||||
* force.
|
||||
*********************************************/
|
||||
// Weights in hectograms
|
||||
// Check to see if the pusher or pushee is a player. 200ish pounds. Steve's like a 6'6 miner
|
||||
var pusherWeight = pusher instanceof PokemonEntity pusherPokemon ? pusherPokemon.getPokemon().getSpecies().getWeight() : 900F;
|
||||
var pusheeWeight = pushee instanceof PokemonEntity pusheePokemon ? pusheePokemon.getPokemon().getSpecies().getWeight() : 900F;
|
||||
|
||||
// Calculate the portion of force received for both entities. Bigger receives less from the
|
||||
// collision than the smaller one.
|
||||
var totalWeight = pusherWeight + pusheeWeight;
|
||||
var pusherReceivedForce = pusheeWeight / totalWeight * 2F;
|
||||
pusheeReceivedForce.set((pusherWeight / totalWeight) * 2F);
|
||||
|
||||
original.call(pusher, -d * pusherReceivedForce, 0.0, -e * pusherReceivedForce);
|
||||
}
|
||||
|
||||
@WrapOperation(
|
||||
method = "push(Lnet/minecraft/world/entity/Entity;)V",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;push(DDD)V", ordinal = 1)
|
||||
)
|
||||
public void cobblemon$customPusheeLogic(Entity pusher, double x, double y, double z, Operation<Void> original,
|
||||
@Local(name = "e") double e, @Local(name = "d") double d,
|
||||
@Share("pusherIsPlayerOrPokemon") LocalBooleanRef pusherIsPlayerOrPokemon,
|
||||
@Share("pusheeIsPlayerOrPokemon") LocalBooleanRef pusheeIsPlayerOrPokemon,
|
||||
@Share("pusheeReceivedForce")LocalFloatRef pusheeReceivedForce) {
|
||||
if (!pusheeIsPlayerOrPokemon.get() || !pusherIsPlayerOrPokemon.get()) {
|
||||
original.call(pusher, x, y, z);
|
||||
return;
|
||||
}
|
||||
|
||||
original.call(pusher, d * pusheeReceivedForce.get(), 0.0, e * pusheeReceivedForce.get());
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
// There appears to be a data driven way to do this now, however I am not sure how it works since there is no wiki or anything so yolo
|
||||
//This is a yucky hack but better than what we were doing before
|
||||
@Mixin(BlockVariantSets.class)
|
||||
public abstract class AdornRegisterInvoker {
|
||||
@Final
|
||||
|
||||
@@ -8,12 +8,8 @@ object CobblemonBuildDetails {
|
||||
const val VERSION = "{{ version }}"
|
||||
const val SNAPSHOT = {{ isSnapshot }}
|
||||
|
||||
// Read at runtime rather than templated in, so a new commit doesn't invalidate compiled code.
|
||||
private val git = java.util.Properties().apply {
|
||||
CobblemonBuildDetails::class.java.getResourceAsStream("/cobblemon-git.properties")?.use(::load)
|
||||
}
|
||||
@JvmField val GIT_COMMIT: String = git.getProperty("commit", "Not Specified")
|
||||
@JvmField val BRANCH: String = git.getProperty("branch", "Not Specified")
|
||||
const val GIT_COMMIT = "{{ gitCommit | default("Not Specified") }}"
|
||||
const val BRANCH = "{{ branch | default("Not Specified") }}"
|
||||
|
||||
fun smallCommitHash(): String {
|
||||
return this.GIT_COMMIT.substring(0, 7)
|
||||
|
||||
@@ -18,7 +18,6 @@ import com.cobblemon.mod.common.api.drop.EvolutionItemDropEntry
|
||||
import com.cobblemon.mod.common.api.drop.ItemDropEntry
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.DATA_SYNCHRONIZED
|
||||
import com.cobblemon.mod.common.api.habitats.HabitatPools
|
||||
import com.cobblemon.mod.common.api.interaction.RequestManager
|
||||
import com.cobblemon.mod.common.api.molang.MoLangLoadedFilesCache
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
@@ -34,7 +33,6 @@ import com.cobblemon.mod.common.api.pokemon.feature.ChoiceSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.FlagSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.IntSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.WeightedChoiceSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.helditem.HeldItemProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.EvCalculator
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Generation8EvCalculator
|
||||
@@ -54,10 +52,6 @@ import com.cobblemon.mod.common.api.storage.adapter.database.MongoDBStoreAdapter
|
||||
import com.cobblemon.mod.common.api.storage.adapter.flatfile.FileStoreAdapter
|
||||
import com.cobblemon.mod.common.api.storage.adapter.flatfile.JSONStoreAdapter
|
||||
import com.cobblemon.mod.common.api.storage.adapter.flatfile.NBTStoreAdapter
|
||||
import com.cobblemon.mod.common.api.storage.egg.EggStoreManager
|
||||
import com.cobblemon.mod.common.api.storage.egg.JsonEggStoreBackend
|
||||
import com.cobblemon.mod.common.api.storage.egg.MongoEggStoreBackend
|
||||
import com.cobblemon.mod.common.api.storage.egg.NbtEggStoreBackend
|
||||
import com.cobblemon.mod.common.api.storage.factory.FileBackedPokemonStoreFactory
|
||||
import com.cobblemon.mod.common.api.storage.molang.NbtMoLangDataStoreFactory
|
||||
import com.cobblemon.mod.common.api.storage.pc.PCStore
|
||||
@@ -68,19 +62,13 @@ import com.cobblemon.mod.common.api.storage.player.adapter.DexDataMongoBackend
|
||||
import com.cobblemon.mod.common.api.storage.player.adapter.DexDataNbtBackend
|
||||
import com.cobblemon.mod.common.api.storage.player.adapter.PlayerDataJsonBackend
|
||||
import com.cobblemon.mod.common.api.storage.player.adapter.PlayerDataMongoBackend
|
||||
import com.cobblemon.mod.common.api.storage.player.adapter.TMMoveMongoBackend
|
||||
import com.cobblemon.mod.common.api.storage.player.adapter.TMMoveNbtBackend
|
||||
import com.cobblemon.mod.common.api.storage.player.factory.CachedPlayerDataStoreFactory
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonEntityTypeTags
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.battles.BagItems
|
||||
import com.cobblemon.mod.common.battles.BattleFormat
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
import com.cobblemon.mod.common.battles.BattleSide
|
||||
import com.cobblemon.mod.common.battles.ShowdownThread
|
||||
import com.cobblemon.mod.common.battles.*
|
||||
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.block.dispenser.DispenserBehaviorRegistry
|
||||
import com.cobblemon.mod.common.block.DispenserBehaviorRegistry
|
||||
import com.cobblemon.mod.common.client.CobblemonPack
|
||||
import com.cobblemon.mod.common.command.argument.*
|
||||
import com.cobblemon.mod.common.config.CobblemonConfig
|
||||
@@ -88,36 +76,22 @@ import com.cobblemon.mod.common.config.LastChangedVersion
|
||||
import com.cobblemon.mod.common.config.constraint.IntConstraint
|
||||
import com.cobblemon.mod.common.config.starter.StarterConfig
|
||||
import com.cobblemon.mod.common.data.CobblemonDataProvider
|
||||
import com.cobblemon.mod.common.events.AdvancementHandler
|
||||
import com.cobblemon.mod.common.events.CallbackHandler
|
||||
import com.cobblemon.mod.common.events.EntityCallbackHandler
|
||||
import com.cobblemon.mod.common.events.PokedexHandler
|
||||
import com.cobblemon.mod.common.events.ServerTickHandler
|
||||
import com.cobblemon.mod.common.events.StatHandler
|
||||
import com.cobblemon.mod.common.events.*
|
||||
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
|
||||
import com.cobblemon.mod.common.permission.LaxPermissionValidator
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.aspects.ALPHA_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.aspects.CHARACTERISTIC_RAINBOW_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.aspects.COSMETIC_SLOT_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.aspects.GENDER_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.aspects.MARK_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.aspects.SHINY_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.BlockClickEvolution
|
||||
import com.cobblemon.mod.common.pokemon.feature.SlowpokeTailRegrowthSpeciesFeature
|
||||
import com.cobblemon.mod.common.pokemon.feature.SlowpokeTailRegrowthSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.pokemon.feature.TagSeasonResolver
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
import com.cobblemon.mod.common.pokemon.properties.AspectPropertyType
|
||||
import com.cobblemon.mod.common.pokemon.properties.BattleCloneProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.FreezeFrameProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.HeldItemVisibleProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.HiddenAbilityPropertyType
|
||||
import com.cobblemon.mod.common.pokemon.properties.LabelProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.NoAIProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.UnaspectPropertyType
|
||||
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.*
|
||||
import com.cobblemon.mod.common.pokemon.properties.tags.PokemonFlagProperty
|
||||
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
|
||||
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
|
||||
import com.cobblemon.mod.common.util.*
|
||||
@@ -128,17 +102,6 @@ import com.mongodb.ConnectionString
|
||||
import com.mongodb.MongoClientSettings
|
||||
import com.mongodb.client.MongoClient
|
||||
import com.mongodb.client.MongoClients
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
import java.io.FileWriter
|
||||
import java.io.PrintWriter
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.properties.Delegates
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
import kotlin.reflect.jvm.javaField
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.commands.synchronization.SingletonArgumentInfo
|
||||
import net.minecraft.resources.ResourceKey
|
||||
@@ -151,6 +114,17 @@ import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.storage.LevelResource
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.apache.logging.log4j.Logger
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
import java.io.FileWriter
|
||||
import java.io.PrintWriter
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.properties.Delegates
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
import kotlin.reflect.jvm.javaField
|
||||
|
||||
object Cobblemon {
|
||||
const val MODID = CobblemonBuildDetails.MOD_ID
|
||||
@@ -179,7 +153,6 @@ object Cobblemon {
|
||||
var storage = PokemonStoreManager()
|
||||
var molangData = NbtMoLangDataStoreFactory
|
||||
lateinit var playerDataManager: PlayerInstancedDataStoreManager
|
||||
lateinit var eggStoreManager: EggStoreManager
|
||||
lateinit var starterConfig: StarterConfig
|
||||
val dataProvider: DataProvider = CobblemonDataProvider
|
||||
var permissionValidator: PermissionValidator by Delegates.observable(LaxPermissionValidator().also { it.initialize() }) { _, _, newValue -> newValue.initialize() }
|
||||
@@ -188,13 +161,11 @@ object Cobblemon {
|
||||
var wallpapers = mutableMapOf<UUID, Set<ResourceLocation>>()
|
||||
|
||||
val serverPlayerStructs = mutableMapOf<UUID, ObjectValue<Player>>()
|
||||
/** Player UUID to entity UUID that they're brain debuggin' */
|
||||
val serverPlayerDebuggingPokemonBrainEntities = mutableMapOf<UUID, UUID>()
|
||||
|
||||
val statistics: CobblemonStats = CobblemonStats
|
||||
|
||||
@JvmStatic
|
||||
val builtinPacks = listOf(
|
||||
val builtinPacks = listOf<CobblemonPack>(
|
||||
CobblemonPack(id = "adorncompatibility", name = "Adorn Compatibility", packType = PackType.CLIENT_RESOURCES, activationBehaviour = ResourcePackActivationBehaviour.ALWAYS_ENABLED, neededMods = setOf("adorn")),
|
||||
CobblemonPack(id = "gyaradosjump", name = "Gyarados Jump Patterns", packType = PackType.CLIENT_RESOURCES, activationBehaviour = ResourcePackActivationBehaviour.DEFAULT_ENABLED),
|
||||
CobblemonPack(id = "regionbiasforms", name = "Region Bias Forms", packType = PackType.CLIENT_RESOURCES, activationBehaviour = ResourcePackActivationBehaviour.DEFAULT_ENABLED),
|
||||
@@ -212,8 +183,6 @@ object Cobblemon {
|
||||
this.LOGGER.info(" - Branch: ${CobblemonBuildDetails.BRANCH}")
|
||||
}
|
||||
|
||||
this.loadConfig()
|
||||
|
||||
implementation.registerRecipeSerializers()
|
||||
implementation.registerRecipeTypes()
|
||||
implementation.registerPermissionValidator()
|
||||
@@ -242,6 +211,7 @@ object Cobblemon {
|
||||
ExperienceGroups.registerDefaults()
|
||||
CaptureCalculators.registerDefaults()
|
||||
|
||||
this.loadConfig()
|
||||
// CobblemonBlockPredicates.touch()
|
||||
CobblemonOrePlacedFeatures.register()
|
||||
CobblemonPlacedFeatures.register()
|
||||
@@ -253,8 +223,6 @@ object Cobblemon {
|
||||
|
||||
DATA_SYNCHRONIZED.subscribe {
|
||||
storage.onPlayerDataSync(it)
|
||||
it.tmList().scheduleFullSyncFromStores(it.party(), it.pc())
|
||||
it.pokedex().scheduleFullSyncFromStores(it.party(), it.pc())
|
||||
playerDataManager.syncAllToPlayer(it)
|
||||
starterHandler.handleJoin(it)
|
||||
it.requestWallpapers()
|
||||
@@ -267,7 +235,6 @@ object Cobblemon {
|
||||
playerDataManager.onPlayerDisconnect(it.player)
|
||||
RequestManager.onLogoff(it.player)
|
||||
serverPlayerStructs.remove(it.player.uuid)
|
||||
serverPlayerDebuggingPokemonBrainEntities.remove(it.player.uuid)
|
||||
}
|
||||
PlatformEvents.PLAYER_DEATH.subscribe {
|
||||
PCLinkManager.removeLink(it.player.uuid)
|
||||
@@ -318,9 +285,6 @@ object Cobblemon {
|
||||
this.config.maxPokemonLevel,
|
||||
this.config.maxPokemonFriendship,
|
||||
this.config.maxDynamaxLevel,
|
||||
this.config.unlockAllMoveDexMovesByDefault,
|
||||
this.config.pokemonIntrinsicSizeMin,
|
||||
this.config.pokemonIntrinsicSizeMax
|
||||
).sendToPlayer(player)
|
||||
}
|
||||
|
||||
@@ -334,11 +298,8 @@ object Cobblemon {
|
||||
GENDER_ASPECT.register()
|
||||
COSMETIC_SLOT_ASPECT.register()
|
||||
CHARACTERISTIC_RAINBOW_ASPECT.register()
|
||||
ALPHA_ASPECT.register()
|
||||
MARK_ASPECT.register()
|
||||
|
||||
SpeciesFeatures.types["choice"] = ChoiceSpeciesFeatureProvider::class.java
|
||||
SpeciesFeatures.types["weighted_choice"] = WeightedChoiceSpeciesFeatureProvider::class.java
|
||||
SpeciesFeatures.types["flag"] = FlagSpeciesFeatureProvider::class.java
|
||||
SpeciesFeatures.types["integer"] = IntSpeciesFeatureProvider::class.java
|
||||
|
||||
@@ -354,13 +315,12 @@ object Cobblemon {
|
||||
|
||||
CustomPokemonProperty.register(UncatchableProperty)
|
||||
CustomPokemonProperty.register(BattleCloneProperty)
|
||||
CustomPokemonProperty.register(LabelProperty)
|
||||
CustomPokemonProperty.register(PokemonFlagProperty)
|
||||
CustomPokemonProperty.register(HiddenAbilityPropertyType)
|
||||
CustomPokemonProperty.register(AspectPropertyType)
|
||||
CustomPokemonProperty.register(UnaspectPropertyType)
|
||||
CustomPokemonProperty.register(FreezeFrameProperty)
|
||||
CustomPokemonProperty.register(NoAIProperty)
|
||||
CustomPokemonProperty.register(HeldItemVisibleProperty)
|
||||
|
||||
CobblemonEvents.POKEMON_PROPERTY_INITIALISED.emit(Unit)
|
||||
|
||||
@@ -382,13 +342,6 @@ object Cobblemon {
|
||||
val server = event.server
|
||||
MoLangLoadedFilesCache.initialize(server)
|
||||
playerDataManager = PlayerInstancedDataStoreManager().also { it.setup(server) }
|
||||
HabitatPools.onServerLoading(server)
|
||||
|
||||
val eggBackend = when (config.storageFormat) {
|
||||
"nbt" -> NbtEggStoreBackend()
|
||||
"json" -> JsonEggStoreBackend()
|
||||
else -> null // MongoDB handled below
|
||||
}
|
||||
|
||||
val mongoClient: MongoClient?
|
||||
|
||||
@@ -401,12 +354,8 @@ object Cobblemon {
|
||||
val pokedexNbtFactory = CachedPlayerDataStoreFactory(DexDataNbtBackend())
|
||||
pokedexNbtFactory.setup(server)
|
||||
|
||||
val tmMoveFactory = CachedPlayerDataStoreFactory(TMMoveNbtBackend())
|
||||
tmMoveFactory.setup(server)
|
||||
|
||||
playerDataManager.setFactory(generalJsonFactory, PlayerInstancedDataStoreTypes.GENERAL)
|
||||
playerDataManager.setFactory(pokedexNbtFactory, PlayerInstancedDataStoreTypes.POKEDEX)
|
||||
playerDataManager.setFactory(tmMoveFactory, PlayerInstancedDataStoreTypes.TM_MOVES)
|
||||
|
||||
if (config.storageFormat == "nbt") {
|
||||
NBTStoreAdapter(pokemonStoreRoot.absolutePath, useNestedFolders = true, folderPerClass = true)
|
||||
@@ -433,18 +382,8 @@ object Cobblemon {
|
||||
val pokedexMongoFactory = CachedPlayerDataStoreFactory(DexDataMongoBackend(mongoClient, config.mongoDBDatabaseName, "PokeDexCollection"))
|
||||
pokedexMongoFactory.setup(server)
|
||||
|
||||
val tmMovesMongoFactory = CachedPlayerDataStoreFactory(
|
||||
TMMoveMongoBackend(mongoClient, config.mongoDBDatabaseName, "TMMovesCollection")
|
||||
)
|
||||
tmMovesMongoFactory.setup(server)
|
||||
|
||||
playerDataManager.setFactory(generalMongoFactory, PlayerInstancedDataStoreTypes.GENERAL)
|
||||
playerDataManager.setFactory(pokedexMongoFactory, PlayerInstancedDataStoreTypes.POKEDEX)
|
||||
playerDataManager.setFactory(tmMovesMongoFactory, PlayerInstancedDataStoreTypes.TM_MOVES)
|
||||
|
||||
eggStoreManager = EggStoreManager(MongoEggStoreBackend(mongoClient, config.mongoDBDatabaseName))
|
||||
eggStoreManager.setup(server)
|
||||
|
||||
MongoDBStoreAdapter(mongoClient, config.mongoDBDatabaseName)
|
||||
} catch (e: ClassNotFoundException) {
|
||||
LOGGER.error("MongoDB driver not found.")
|
||||
@@ -458,11 +397,6 @@ object Cobblemon {
|
||||
}
|
||||
.with(ReforgedConversion(server.getWorldPath(LevelResource.ROOT))) as FileStoreAdapter<*>
|
||||
|
||||
if (eggBackend != null) {
|
||||
eggStoreManager = EggStoreManager(eggBackend)
|
||||
eggStoreManager.setup(server)
|
||||
}
|
||||
|
||||
storage.registerFactory(
|
||||
priority = Priority.LOWEST,
|
||||
factory = FileBackedPokemonStoreFactory(
|
||||
@@ -475,7 +409,6 @@ object Cobblemon {
|
||||
|
||||
PlatformEvents.SERVER_STOPPED.subscribe {
|
||||
storage.unregisterAll(it.server.registryAccess())
|
||||
eggStoreManager.shutdown()
|
||||
playerDataManager.saveAllStores()
|
||||
playerDataManager.saveExecutor.shutdown()
|
||||
playerDataManager.saveExecutor.awaitTermination(30L, TimeUnit.SECONDS)
|
||||
@@ -518,7 +451,7 @@ object Cobblemon {
|
||||
server()?.getLevel(dimension)
|
||||
} else {
|
||||
val mc = Minecraft.getInstance()
|
||||
mc.singleplayerServer?.getLevel(dimension) ?: mc.level
|
||||
return mc.singleplayerServer?.getLevel(dimension) ?: mc.level
|
||||
}
|
||||
}
|
||||
|
||||
@@ -634,7 +567,6 @@ object Cobblemon {
|
||||
this.implementation.registerCommandArgument(cobblemonResource("mark"), MarkArgumentType::class, SingletonArgumentInfo.contextFree(MarkArgumentType::mark))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("transform_type"), TransformTypeArgumentType::class, SingletonArgumentInfo.contextFree(TransformTypeArgumentType::transformType))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("model_part"), ModelPartArgumentType::class, SingletonArgumentInfo.contextFree(ModelPartArgumentType::modelPart))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("tm"), TmArgumentType::class, SingletonArgumentInfo.contextFree(TmArgumentType::tm))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,8 +12,6 @@ import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.ai.CobblemonBehaviour
|
||||
import com.cobblemon.mod.common.api.ai.config.BehaviourConfig
|
||||
import com.cobblemon.mod.common.api.ai.config.objective.ObjectiveConfig
|
||||
import com.cobblemon.mod.common.api.ai.config.sense.SenseConfig
|
||||
import com.cobblemon.mod.common.api.ai.config.task.TaskConfig
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry.Companion.JSON_EXTENSION
|
||||
@@ -28,8 +26,6 @@ import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionOrEntityVariableAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.MemoryModuleTypeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ObjectiveConfigAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.SenseConfigAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.SensorTypeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.TaskConfigAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.TranslatedTextAdapter
|
||||
@@ -59,8 +55,6 @@ object CobblemonBehaviours : JsonDataRegistry<CobblemonBehaviour> {
|
||||
.registerTypeAdapter(SensorType::class.java, SensorTypeAdapter)
|
||||
.registerTypeAdapter(BehaviourConfig::class.java, BehaviourConfigAdapter)
|
||||
.registerTypeAdapter(TaskConfig::class.java, TaskConfigAdapter)
|
||||
.registerTypeAdapter(ObjectiveConfig::class.java, ObjectiveConfigAdapter)
|
||||
.registerTypeAdapter(SenseConfig::class.java, SenseConfigAdapter)
|
||||
.registerTypeAdapter(
|
||||
TypeToken.getParameterized(Either::class.java, Expression::class.java, MoLangConfigVariable::class.java).type,
|
||||
ExpressionOrEntityVariableAdapter
|
||||
|
||||
@@ -8,16 +8,22 @@
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.block.entity.BerryBlockEntity
|
||||
import com.cobblemon.mod.common.block.entity.HealingMachineBlockEntity
|
||||
import com.cobblemon.mod.common.block.entity.PCBlockEntity
|
||||
import com.cobblemon.mod.common.block.entity.PokemonPastureBlockEntity
|
||||
import com.cobblemon.mod.common.block.entity.FossilAnalyzerBlockEntity
|
||||
import com.cobblemon.mod.common.block.entity.FossilMultiblockEntity
|
||||
import com.cobblemon.mod.common.block.entity.RestorationTankBlockEntity
|
||||
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockBuilder
|
||||
import com.cobblemon.mod.common.block.entity.*
|
||||
import com.cobblemon.mod.common.block.entity.DisplayCaseBlockEntity
|
||||
import com.cobblemon.mod.common.block.habitat.HabitatBlockEntity
|
||||
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockBuilder
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import net.minecraft.core.Registry
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.resources.ResourceKey
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||
import net.minecraft.resources.ResourceKey
|
||||
|
||||
object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, ResourceKey<Registry<BlockEntityType<*>>>, BlockEntityType<*>>() {
|
||||
|
||||
@@ -33,9 +39,6 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
|
||||
@JvmField
|
||||
val LECTERN: BlockEntityType<LecternBlockEntity> = this.create("lectern", BlockEntityType.Builder.of(::LecternBlockEntity, CobblemonBlocks.LECTERN).build(null))
|
||||
|
||||
@JvmField
|
||||
val DISC_SHELF: BlockEntityType<DiscShelfBlockEntity> = this.create("disc_shelf", BlockEntityType.Builder.of(::DiscShelfBlockEntity, CobblemonBlocks.DISC_SHELF).build(null))
|
||||
|
||||
@JvmField
|
||||
val BERRY = this.create("berry", BlockEntityType.Builder.of(::BerryBlockEntity, *CobblemonBlocks.berries().values.toTypedArray()).build(null))
|
||||
|
||||
@@ -45,12 +48,7 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
|
||||
val SIGN: BlockEntityType<CobblemonSignBlockEntity> = this.create("sign", BlockEntityType.Builder.of(::CobblemonSignBlockEntity, CobblemonBlocks.APRICORN_SIGN, CobblemonBlocks.APRICORN_WALL_SIGN, CobblemonBlocks.SACCHARINE_SIGN, CobblemonBlocks.SACCHARINE_WALL_SIGN).build(null))
|
||||
@JvmField
|
||||
val HANGING_SIGN: BlockEntityType<CobblemonHangingSignBlockEntity> = this.create("hanging_sign", BlockEntityType.Builder.of(::CobblemonHangingSignBlockEntity, CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN, CobblemonBlocks.SACCHARINE_HANGING_SIGN, CobblemonBlocks.SACCHARINE_WALL_HANGING_SIGN).build(null))
|
||||
@JvmField
|
||||
val TM_MACHINE: BlockEntityType<TMMachineBlockEntity> = this.create("tm_machine", BlockEntityType.Builder.of(::TMMachineBlockEntity, CobblemonBlocks.TM_MACHINE).build(null))
|
||||
@JvmField
|
||||
val HABITAT_BLOCK: BlockEntityType<HabitatBlockEntity> = this.create("habitat_block",
|
||||
BlockEntityType.Builder.of(::HabitatBlockEntity, CobblemonBlocks.HABITAT_BLOCK).build(null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val GILDED_CHEST: BlockEntityType<GildedChestBlockEntity> = this.create("chest", BlockEntityType.Builder.of(::GildedChestBlockEntity,
|
||||
CobblemonBlocks.GILDED_CHEST,
|
||||
@@ -84,38 +82,6 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
|
||||
).build(null)
|
||||
)
|
||||
|
||||
val NEST: BlockEntityType<NestBlockEntity> = this.create("nest",
|
||||
BlockEntityType.Builder.of(
|
||||
::NestBlockEntity,
|
||||
CobblemonBlocks.NEST_FIERY,
|
||||
CobblemonBlocks.NEST_GRASSY,
|
||||
CobblemonBlocks.NEST_LEAFY,
|
||||
CobblemonBlocks.NEST_ICY,
|
||||
CobblemonBlocks.NEST_ROCKY,
|
||||
CobblemonBlocks.NEST_SANDY,
|
||||
CobblemonBlocks.NEST_SHROOMY,
|
||||
CobblemonBlocks.NEST_TWIGGY,
|
||||
CobblemonBlocks.NEST_HAY,
|
||||
CobblemonBlocks.NEST_KELP,
|
||||
CobblemonBlocks.NEST_WATERY
|
||||
).build(null))
|
||||
|
||||
val EGG: BlockEntityType<EggBlockEntity> = this.create("egg",
|
||||
BlockEntityType.Builder.of(
|
||||
::EggBlockEntity,
|
||||
CobblemonBlocks.EGG
|
||||
).build(null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val INCUBATOR: BlockEntityType<IncubatorBlockEntity> = this.create("incubator",
|
||||
BlockEntityType.Builder.of(
|
||||
::IncubatorBlockEntity,
|
||||
CobblemonBlocks.INCUBATOR
|
||||
).build(null)
|
||||
)
|
||||
|
||||
|
||||
@JvmField
|
||||
val DISPLAY_CASE: BlockEntityType<DisplayCaseBlockEntity> = this.create("display_case",
|
||||
BlockEntityType.Builder.of(::DisplayCaseBlockEntity, CobblemonBlocks.DISPLAY_CASE).build(null)
|
||||
|
||||
@@ -9,74 +9,21 @@
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.api.apricorn.Apricorn
|
||||
import com.cobblemon.mod.common.api.nest.WildNestType
|
||||
import com.cobblemon.mod.common.api.nest.WildNestVariant
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.block.ApricornBlock
|
||||
import com.cobblemon.mod.common.block.ApricornSaplingBlock
|
||||
import com.cobblemon.mod.common.block.BerryBlock
|
||||
import com.cobblemon.mod.common.block.BigRootBlock
|
||||
import com.cobblemon.mod.common.block.CoinPouchBlock
|
||||
import com.cobblemon.mod.common.block.DamagedMonitorBlock
|
||||
import com.cobblemon.mod.common.block.DecorativeItemBlock
|
||||
import com.cobblemon.mod.common.block.DiscShelfBlock
|
||||
import com.cobblemon.mod.common.block.DisplayCaseBlock
|
||||
import com.cobblemon.mod.common.block.EggBlock
|
||||
import com.cobblemon.mod.common.block.EjectButtonBlock
|
||||
import com.cobblemon.mod.common.block.EnergyRootBlock
|
||||
import com.cobblemon.mod.common.block.FossilAnalyzerBlock
|
||||
import com.cobblemon.mod.common.block.GalaricaWreathBlock
|
||||
import com.cobblemon.mod.common.block.HealingMachineBlock
|
||||
import com.cobblemon.mod.common.block.HeartyGrainsBlock
|
||||
import com.cobblemon.mod.common.block.IncubatorBlock
|
||||
import com.cobblemon.mod.common.block.LecternBlock
|
||||
import com.cobblemon.mod.common.block.MagnetBlock
|
||||
import com.cobblemon.mod.common.block.MedicinalLeekBlock
|
||||
import com.cobblemon.mod.common.block.MintBlock
|
||||
import com.cobblemon.mod.common.block.MintBlock.MintType
|
||||
import com.cobblemon.mod.common.block.MonitorBlock
|
||||
import com.cobblemon.mod.common.block.NestBlock
|
||||
import com.cobblemon.mod.common.block.NutBushBlock
|
||||
import com.cobblemon.mod.common.block.OrbBlock
|
||||
import com.cobblemon.mod.common.block.PCBlock
|
||||
import com.cobblemon.mod.common.block.PastureBlock
|
||||
import com.cobblemon.mod.common.block.PlaqueBlock
|
||||
import com.cobblemon.mod.common.block.PokeSnackBlock
|
||||
import com.cobblemon.mod.common.block.RestorationTankBlock
|
||||
import com.cobblemon.mod.common.block.RevivalHerbBlock
|
||||
import com.cobblemon.mod.common.block.SaccharineLeafBlock
|
||||
import com.cobblemon.mod.common.block.SaccharineLogBlock
|
||||
import com.cobblemon.mod.common.block.SaccharineLogSlatheredBlock
|
||||
import com.cobblemon.mod.common.block.ScarekrowBlock
|
||||
import com.cobblemon.mod.common.block.StackableItemBlock
|
||||
import com.cobblemon.mod.common.block.TumblestoneBlock
|
||||
import com.cobblemon.mod.common.block.TypeGemClusterBlock
|
||||
import com.cobblemon.mod.common.block.TypeGemCoreBlock
|
||||
import com.cobblemon.mod.common.block.VivichokeBlock
|
||||
import com.cobblemon.mod.common.block.WallAttachedDirectionalShapeBlock
|
||||
import com.cobblemon.mod.common.block.WallAttachedStackableItemBlock
|
||||
import com.cobblemon.mod.common.block.WildNestBlock
|
||||
import com.cobblemon.mod.common.block.*
|
||||
import com.cobblemon.mod.common.block.campfirepot.CampfireBlock
|
||||
import com.cobblemon.mod.common.block.LecternBlock
|
||||
import com.cobblemon.mod.common.block.MintBlock.MintType
|
||||
import com.cobblemon.mod.common.block.campfirepot.CampfirePotBlock
|
||||
import com.cobblemon.mod.common.block.chest.GildedChestBlock
|
||||
import com.cobblemon.mod.common.block.decor.ActivatableDecorationBlock
|
||||
import com.cobblemon.mod.common.block.decor.RingTargetBlock
|
||||
import com.cobblemon.mod.common.block.general.BaleBlock
|
||||
import com.cobblemon.mod.common.block.general.HorizontalRotationCarpetBlock
|
||||
import com.cobblemon.mod.common.block.general.HorizontalRotationalBlock
|
||||
import com.cobblemon.mod.common.block.grower.SaccharineTreeGrower
|
||||
import com.cobblemon.mod.common.block.habitat.HabitatBlock
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonHangingSignBlock
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonSignBlock
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonWallHangingSignBlock
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonWallSignBlock
|
||||
import com.cobblemon.mod.common.block.tmmachine.TMMachineBlock
|
||||
import com.cobblemon.mod.common.mixin.invoker.BlocksInvoker
|
||||
import com.cobblemon.mod.common.mixin.invoker.DoorBlockInvoker
|
||||
import com.cobblemon.mod.common.mixin.invoker.FireBlockInvoker
|
||||
import com.cobblemon.mod.common.mixin.invoker.PressurePlateBlockInvoker
|
||||
import com.cobblemon.mod.common.mixin.invoker.StairsBlockInvoker
|
||||
import com.cobblemon.mod.common.mixin.invoker.TrapdoorBlockInvoker
|
||||
import com.cobblemon.mod.common.block.general.HorizontalRotationCarpetBlock
|
||||
import com.cobblemon.mod.common.block.general.HorizontalRotationalBlock
|
||||
import com.cobblemon.mod.common.mixin.invoker.*
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.core.BlockPos
|
||||
@@ -94,6 +41,7 @@ import net.minecraft.world.level.block.state.BlockBehaviour
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.properties.BlockSetType
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties.LIT
|
||||
import net.minecraft.world.level.block.state.properties.NoteBlockInstrument
|
||||
import net.minecraft.world.level.block.state.properties.WoodType
|
||||
import net.minecraft.world.level.material.MapColor
|
||||
@@ -172,19 +120,19 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
val APRICORN_PLANKS = this.create("apricorn_planks",
|
||||
Block(
|
||||
BlockBehaviour.Properties.of().mapColor(MapColor.DIRT).instrument(NoteBlockInstrument.BASS)
|
||||
.strength(2.0F, 3.0F).sound(SoundType.WOOD)
|
||||
.strength(2.0f, 3.0f).sound(SoundType.WOOD)
|
||||
)
|
||||
)
|
||||
@JvmField
|
||||
val APRICORN_LEAVES = leaves("apricorn_leaves")
|
||||
@JvmField
|
||||
val APRICORN_FENCE = this.create("apricorn_fence", FenceBlock(BlockBehaviour.Properties.of().mapColor(APRICORN_PLANKS.defaultMapColor()).instrument(NoteBlockInstrument.BASS).strength(2.0F, 3.0F).sound(SoundType.WOOD)))
|
||||
val APRICORN_FENCE = this.create("apricorn_fence", FenceBlock(BlockBehaviour.Properties.of().mapColor(APRICORN_PLANKS.defaultMapColor()).instrument(NoteBlockInstrument.BASS).strength(2.0f, 3.0f).sound(SoundType.WOOD)))
|
||||
@JvmField
|
||||
val APRICORN_FENCE_GATE = this.create("apricorn_fence_gate", FenceGateBlock(APRICORN_WOOD_TYPE, BlockBehaviour.Properties.of().mapColor(APRICORN_PLANKS.defaultMapColor()).strength(2.0F, 3.0F).sound(SoundType.WOOD).ignitedByLava().forceSolidOn()))
|
||||
val APRICORN_FENCE_GATE = this.create("apricorn_fence_gate", FenceGateBlock(APRICORN_WOOD_TYPE, BlockBehaviour.Properties.of().mapColor(APRICORN_PLANKS.defaultMapColor()).strength(2.0f, 3.0f).sound(SoundType.WOOD).ignitedByLava().forceSolidOn()))
|
||||
@JvmField
|
||||
val APRICORN_BUTTON = this.create("apricorn_button", BlocksInvoker.createWoodenButtonBlock(APRICORN_BLOCK_SET_TYPE))
|
||||
@JvmField
|
||||
val APRICORN_PRESSURE_PLATE = this.create("apricorn_pressure_plate", PressurePlateBlockInvoker.`cobblemon$create`(APRICORN_BLOCK_SET_TYPE, BlockBehaviour.Properties.of().mapColor(APRICORN_PLANKS.defaultMapColor()).noCollission().strength(0.5F).sound(SoundType.WOOD)))
|
||||
val APRICORN_PRESSURE_PLATE = this.create("apricorn_pressure_plate", PressurePlateBlockInvoker.`cobblemon$create`(APRICORN_BLOCK_SET_TYPE, BlockBehaviour.Properties.of().mapColor(APRICORN_PLANKS.defaultMapColor()).noCollission().strength(0.5f).sound(SoundType.WOOD)))
|
||||
@JvmField
|
||||
val APRICORN_SIGN = this.create("apricorn_sign", CobblemonSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_SIGN), APRICORN_WOOD_TYPE))
|
||||
|
||||
@@ -201,7 +149,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
@JvmField
|
||||
val APRICORN_WALL_HANGING_SIGN = this.create("apricorn_wall_hanging_sign", CobblemonWallHangingSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_HANGING_SIGN), APRICORN_WOOD_TYPE))
|
||||
@JvmField
|
||||
val APRICORN_SLAB = this.create("apricorn_slab", SlabBlock(BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).strength(2.0F, 3.0F).sound(SoundType.WOOD)))
|
||||
val APRICORN_SLAB = this.create("apricorn_slab", SlabBlock(BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).strength(2.0f, 3.0f).sound(SoundType.WOOD)))
|
||||
@JvmField
|
||||
val APRICORN_STAIRS = this.create("apricorn_stairs", StairsBlockInvoker.`cobblemon$create`(APRICORN_PLANKS.defaultBlockState(), BlockBehaviour.Properties.ofFullCopy(APRICORN_PLANKS)))
|
||||
@JvmField
|
||||
@@ -238,12 +186,12 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
@JvmField
|
||||
val STRIPPED_SACCHARINE_WOOD = this.create("stripped_saccharine_wood", RotatedPillarBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_LIGHT_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0F).sound(SoundType.WOOD).ignitedByLava())) //log("stripped_saccharine_log")
|
||||
@JvmField
|
||||
val SACCHARINE_PLANKS = this.create("saccharine_planks", Block(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_LIGHT_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0F, 3.0F).sound(SoundType.WOOD)))
|
||||
val SACCHARINE_PLANKS = this.create("saccharine_planks", Block(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_LIGHT_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0f, 3.0f).sound(SoundType.WOOD)))
|
||||
@JvmField
|
||||
val SACCHARINE_LEAVES = this.create("saccharine_leaves", SaccharineLeafBlock(
|
||||
BlockBehaviour.Properties.of().mapColor(
|
||||
MapColor.PLANT
|
||||
).strength(0.2F).randomTicks().sound(SoundType.GRASS).noOcclusion()
|
||||
).strength(0.2f).randomTicks().sound(SoundType.GRASS).noOcclusion()
|
||||
.isValidSpawn { _: BlockState?, _: BlockGetter?, _: BlockPos?, entity: EntityType<*>? ->
|
||||
entity === EntityType.OCELOT || entity === EntityType.PARROT
|
||||
}.isSuffocating { _: BlockState?, _: BlockGetter?, _: BlockPos? ->
|
||||
@@ -255,13 +203,13 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
false
|
||||
}))
|
||||
@JvmField
|
||||
val SACCHARINE_FENCE = this.create("saccharine_fence", FenceBlock(BlockBehaviour.Properties.of().mapColor(SACCHARINE_PLANKS.defaultMapColor()).instrument(NoteBlockInstrument.BASS).strength(2.0F, 3.0F).sound(SoundType.WOOD)))
|
||||
val SACCHARINE_FENCE = this.create("saccharine_fence", FenceBlock(BlockBehaviour.Properties.of().mapColor(SACCHARINE_PLANKS.defaultMapColor()).instrument(NoteBlockInstrument.BASS).strength(2.0f, 3.0f).sound(SoundType.WOOD)))
|
||||
@JvmField
|
||||
val SACCHARINE_FENCE_GATE = this.create("saccharine_fence_gate", FenceGateBlock(SACCHARINE_WOOD_TYPE, BlockBehaviour.Properties.of().mapColor(SACCHARINE_PLANKS.defaultMapColor()).instrument(NoteBlockInstrument.BASS).strength(2.0F, 3.0F).sound(SoundType.WOOD).ignitedByLava().forceSolidOn()))
|
||||
val SACCHARINE_FENCE_GATE = this.create("saccharine_fence_gate", FenceGateBlock(SACCHARINE_WOOD_TYPE, BlockBehaviour.Properties.of().mapColor(SACCHARINE_PLANKS.defaultMapColor()).instrument(NoteBlockInstrument.BASS).strength(2.0f, 3.0f).sound(SoundType.WOOD).ignitedByLava().forceSolidOn()))
|
||||
@JvmField
|
||||
val SACCHARINE_BUTTON = this.create("saccharine_button", BlocksInvoker.createWoodenButtonBlock(BlockSetType.OAK))
|
||||
@JvmField
|
||||
val SACCHARINE_PRESSURE_PLATE = this.create("saccharine_pressure_plate", PressurePlateBlockInvoker.`cobblemon$create`(SACCHARINE_BLOCK_SET_TYPE, BlockBehaviour.Properties.of().mapColor(SACCHARINE_PLANKS.defaultMapColor()).instrument(NoteBlockInstrument.BASS).noCollission().strength(0.5F).sound(SoundType.WOOD)))
|
||||
val SACCHARINE_PRESSURE_PLATE = this.create("saccharine_pressure_plate", PressurePlateBlockInvoker.`cobblemon$create`(SACCHARINE_BLOCK_SET_TYPE, BlockBehaviour.Properties.of().mapColor(SACCHARINE_PLANKS.defaultMapColor()).instrument(NoteBlockInstrument.BASS).noCollission().strength(0.5f).sound(SoundType.WOOD)))
|
||||
@JvmField
|
||||
val SACCHARINE_SIGN = this.create("saccharine_sign", CobblemonSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_SIGN), SACCHARINE_WOOD_TYPE))
|
||||
@JvmField
|
||||
@@ -271,7 +219,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
@JvmField
|
||||
val SACCHARINE_WALL_HANGING_SIGN = this.create("saccharine_wall_hanging_sign", CobblemonWallHangingSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_HANGING_SIGN), SACCHARINE_WOOD_TYPE))
|
||||
@JvmField
|
||||
val SACCHARINE_SLAB = this.create("saccharine_slab", SlabBlock(BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).strength(2.0F, 3.0F).sound(SoundType.WOOD)))
|
||||
val SACCHARINE_SLAB = this.create("saccharine_slab", SlabBlock(BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).strength(2.0f, 3.0f).sound(SoundType.WOOD)))
|
||||
@JvmField
|
||||
val SACCHARINE_STAIRS = this.create("saccharine_stairs", StairsBlockInvoker.`cobblemon$create`(SACCHARINE_PLANKS.defaultBlockState(), BlockBehaviour.Properties.ofFullCopy(SACCHARINE_PLANKS)))
|
||||
@JvmField
|
||||
@@ -295,36 +243,36 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
val REVIVAL_HERB = this.create("revival_herb", RevivalHerbBlock(BlockBehaviour.Properties.of().pushReaction(PushReaction.DESTROY).mapColor(MapColor.PLANT).ignitedByLava().noCollission().instabreak().sound(CobblemonSounds.REVIVAL_HERB_SOUNDS)))
|
||||
|
||||
@JvmField
|
||||
val POKE_CAKE = this.create("poke_cake", PokeSnackBlock(BlockBehaviour.Properties.of().forceSolidOn().strength(0.5F).sound(SoundType.WOOL).pushReaction(PushReaction.DESTROY).lightLevel { if (it.getValue(BlockStateProperties.LIT)) 3 else 0 }, false))
|
||||
val POKE_CAKE = this.create("poke_cake", PokeSnackBlock(BlockBehaviour.Properties.of().forceSolidOn().strength(0.5F).sound(SoundType.WOOL).pushReaction(PushReaction.DESTROY).lightLevel { if (it.getValue(LIT)) 3 else 0 }, false))
|
||||
@JvmField
|
||||
val POKE_SNACK = this.create("poke_snack", PokeSnackBlock(BlockBehaviour.Properties.of().forceSolidOn().strength(0.5F).sound(SoundType.WOOL).pushReaction(PushReaction.DESTROY).lightLevel { if (it.getValue(BlockStateProperties.LIT)) 3 else 0 }, true))
|
||||
val POKE_SNACK = this.create("poke_snack", PokeSnackBlock(BlockBehaviour.Properties.of().forceSolidOn().strength(0.5F).sound(SoundType.WOOL).pushReaction(PushReaction.DESTROY).lightLevel { if (it.getValue(LIT)) 3 else 0 }, true))
|
||||
|
||||
@JvmField
|
||||
val TUMBLESTONE_CLUSTER = tumblestoneBlock("tumblestone_cluster", TumblestoneBlock.STAGE_3, 7, 3, null, MapColor.TERRACOTTA_ORANGE)
|
||||
val TUMBLESTONE_CLUSTER = tumblestoneBlock("tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
|
||||
@JvmField
|
||||
val LARGE_BUDDING_TUMBLESTONE = tumblestoneBlock("large_budding_tumblestone", TumblestoneBlock.STAGE_2, 5, 3, TUMBLESTONE_CLUSTER, MapColor.TERRACOTTA_ORANGE)
|
||||
val LARGE_BUDDING_TUMBLESTONE = tumblestoneBlock("large_budding_tumblestone", GrowableStoneBlock.STAGE_2, 5, 3, TUMBLESTONE_CLUSTER)
|
||||
@JvmField
|
||||
val MEDIUM_BUDDING_TUMBLESTONE = tumblestoneBlock("medium_budding_tumblestone", TumblestoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_TUMBLESTONE, MapColor.TERRACOTTA_ORANGE)
|
||||
val MEDIUM_BUDDING_TUMBLESTONE = tumblestoneBlock("medium_budding_tumblestone", GrowableStoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_TUMBLESTONE)
|
||||
@JvmField
|
||||
val SMALL_BUDDING_TUMBLESTONE = tumblestoneBlock("small_budding_tumblestone", TumblestoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_TUMBLESTONE, MapColor.TERRACOTTA_ORANGE)
|
||||
val SMALL_BUDDING_TUMBLESTONE = tumblestoneBlock("small_budding_tumblestone", GrowableStoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_TUMBLESTONE)
|
||||
|
||||
@JvmField
|
||||
val SKY_TUMBLESTONE_CLUSTER = tumblestoneBlock("sky_tumblestone_cluster", TumblestoneBlock.STAGE_3, 7, 3, null, MapColor.COLOR_LIGHT_BLUE)
|
||||
val SKY_TUMBLESTONE_CLUSTER = tumblestoneBlock("sky_tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
|
||||
@JvmField
|
||||
val LARGE_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("large_budding_sky_tumblestone", TumblestoneBlock.STAGE_2, 5, 3, SKY_TUMBLESTONE_CLUSTER, MapColor.COLOR_LIGHT_BLUE)
|
||||
val LARGE_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("large_budding_sky_tumblestone", GrowableStoneBlock.STAGE_2, 5, 3, SKY_TUMBLESTONE_CLUSTER)
|
||||
@JvmField
|
||||
val MEDIUM_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("medium_budding_sky_tumblestone", TumblestoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_SKY_TUMBLESTONE, MapColor.COLOR_LIGHT_BLUE)
|
||||
val MEDIUM_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("medium_budding_sky_tumblestone", GrowableStoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_SKY_TUMBLESTONE)
|
||||
@JvmField
|
||||
val SMALL_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("small_budding_sky_tumblestone", TumblestoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_SKY_TUMBLESTONE, MapColor.COLOR_LIGHT_BLUE)
|
||||
val SMALL_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("small_budding_sky_tumblestone", GrowableStoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_SKY_TUMBLESTONE)
|
||||
|
||||
@JvmField
|
||||
val BLACK_TUMBLESTONE_CLUSTER = tumblestoneBlock("black_tumblestone_cluster", TumblestoneBlock.STAGE_3, 7, 3, null, MapColor.TERRACOTTA_BLACK)
|
||||
val BLACK_TUMBLESTONE_CLUSTER = tumblestoneBlock("black_tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
|
||||
@JvmField
|
||||
val LARGE_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("large_budding_black_tumblestone", TumblestoneBlock.STAGE_2, 5, 3, BLACK_TUMBLESTONE_CLUSTER, MapColor.TERRACOTTA_BLACK)
|
||||
val LARGE_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("large_budding_black_tumblestone", GrowableStoneBlock.STAGE_2, 5, 3, BLACK_TUMBLESTONE_CLUSTER)
|
||||
@JvmField
|
||||
val MEDIUM_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("medium_budding_black_tumblestone", TumblestoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_BLACK_TUMBLESTONE, MapColor.TERRACOTTA_BLACK)
|
||||
val MEDIUM_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("medium_budding_black_tumblestone", GrowableStoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_BLACK_TUMBLESTONE)
|
||||
@JvmField
|
||||
val SMALL_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("small_budding_black_tumblestone", TumblestoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_BLACK_TUMBLESTONE, MapColor.TERRACOTTA_BLACK)
|
||||
val SMALL_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("small_budding_black_tumblestone", GrowableStoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_BLACK_TUMBLESTONE)
|
||||
|
||||
@JvmField
|
||||
val TUMBLESTONE_BLOCK = this.create("tumblestone_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_ORANGE).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@@ -333,87 +281,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
@JvmField
|
||||
val BLACK_TUMBLESTONE_BLOCK = this.create("black_tumblestone_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
|
||||
@JvmField
|
||||
val TYPE_GEM_CORE = this.create("deepslate_crystal_core", TypeGemCoreBlock(BlockBehaviour.Properties.of().strength(4.0F, 10.0F).requiresCorrectToolForDrops().mapColor(MapColor.DEEPSLATE)))
|
||||
|
||||
private val typeGemBlocks = mutableMapOf<ResourceLocation, Block>()
|
||||
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_NORMAL = typeGemBlock("normal_gem_block", MapColor.QUARTZ)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_FIRE = typeGemBlock("fire_gem_block", MapColor.FIRE)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_WATER = typeGemBlock("water_gem_block", MapColor.WATER)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_GRASS = typeGemBlock("grass_gem_block", MapColor.COLOR_LIGHT_GREEN)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_ELECTRIC = typeGemBlock("electric_gem_block", MapColor.GOLD)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_ICE = typeGemBlock("ice_gem_block", MapColor.ICE)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_FIGHTING = typeGemBlock("fighting_gem_block", MapColor.COLOR_RED)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_POISON = typeGemBlock("poison_gem_block", MapColor.COLOR_PURPLE)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_GROUND = typeGemBlock("ground_gem_block", MapColor.PODZOL)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_FLYING = typeGemBlock("flying_gem_block", MapColor.COLOR_LIGHT_BLUE)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_PSYCHIC = typeGemBlock("psychic_gem_block", MapColor.COLOR_MAGENTA)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_BUG = typeGemBlock("bug_gem_block", MapColor.TERRACOTTA_LIGHT_GREEN)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_ROCK = typeGemBlock("rock_gem_block", MapColor.TERRACOTTA_LIGHT_GRAY)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_GHOST = typeGemBlock("ghost_gem_block", MapColor.TERRACOTTA_MAGENTA)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_DRAGON = typeGemBlock("dragon_gem_block", MapColor.COLOR_BLUE)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_DARK = typeGemBlock("dark_gem_block", MapColor.TERRACOTTA_BLACK)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_STEEL = typeGemBlock("steel_gem_block", MapColor.METAL)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_FAIRY = typeGemBlock("fairy_gem_block", MapColor.COLOR_PINK)
|
||||
|
||||
private val typeGemClusters = mutableMapOf<ResourceLocation, TypeGemClusterBlock>()
|
||||
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_NORMAL = typeGemCluster("normal_gem_cluster", TYPE_GEM_BLOCK_NORMAL, cobblemonResource("normal_gem"), MapColor.QUARTZ)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_FIRE = typeGemCluster("fire_gem_cluster", TYPE_GEM_BLOCK_FIRE, cobblemonResource("fire_gem"), MapColor.FIRE)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_WATER = typeGemCluster("water_gem_cluster", TYPE_GEM_BLOCK_WATER, cobblemonResource("water_gem"), MapColor.WATER)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_GRASS = typeGemCluster("grass_gem_cluster", TYPE_GEM_BLOCK_GRASS, cobblemonResource("grass_gem"), MapColor.COLOR_LIGHT_GREEN)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_ELECTRIC = typeGemCluster("electric_gem_cluster", TYPE_GEM_BLOCK_ELECTRIC, cobblemonResource("electric_gem"), MapColor.GOLD)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_ICE = typeGemCluster("ice_gem_cluster", TYPE_GEM_BLOCK_ICE, cobblemonResource("ice_gem"), MapColor.ICE)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_FIGHTING = typeGemCluster("fighting_gem_cluster", TYPE_GEM_BLOCK_FIGHTING, cobblemonResource("fighting_gem"), MapColor.COLOR_RED)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_POISON = typeGemCluster("poison_gem_cluster", TYPE_GEM_BLOCK_POISON, cobblemonResource("poison_gem"), MapColor.COLOR_PURPLE)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_GROUND = typeGemCluster("ground_gem_cluster", TYPE_GEM_BLOCK_GROUND, cobblemonResource("ground_gem"), MapColor.PODZOL)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_FLYING = typeGemCluster("flying_gem_cluster", TYPE_GEM_BLOCK_FLYING, cobblemonResource("flying_gem"), MapColor.COLOR_LIGHT_BLUE)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_PSYCHIC = typeGemCluster("psychic_gem_cluster", TYPE_GEM_BLOCK_PSYCHIC, cobblemonResource("psychic_gem"), MapColor.COLOR_MAGENTA)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_BUG = typeGemCluster("bug_gem_cluster", TYPE_GEM_BLOCK_BUG, cobblemonResource("bug_gem"), MapColor.TERRACOTTA_LIGHT_GREEN)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_ROCK = typeGemCluster("rock_gem_cluster", TYPE_GEM_BLOCK_ROCK, cobblemonResource("rock_gem"), MapColor.TERRACOTTA_LIGHT_GRAY)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_GHOST = typeGemCluster("ghost_gem_cluster", TYPE_GEM_BLOCK_GHOST, cobblemonResource("ghost_gem"), MapColor.TERRACOTTA_MAGENTA)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_DRAGON = typeGemCluster("dragon_gem_cluster", TYPE_GEM_BLOCK_DRAGON, cobblemonResource("dragon_gem"), MapColor.COLOR_BLUE)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_DARK = typeGemCluster("dark_gem_cluster", TYPE_GEM_BLOCK_DARK, cobblemonResource("dark_gem"), MapColor.TERRACOTTA_BLACK)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_STEEL = typeGemCluster("steel_gem_cluster", TYPE_GEM_BLOCK_STEEL, cobblemonResource("steel_gem"), MapColor.METAL)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_FAIRY = typeGemCluster("fairy_gem_cluster", TYPE_GEM_BLOCK_FAIRY, cobblemonResource("fairy_gem"), MapColor.COLOR_PINK)
|
||||
|
||||
@JvmField
|
||||
val POLISHED_TUMBLESTONE = this.create("polished_tumblestone", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_ORANGE).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
@@ -582,18 +449,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val HABITAT_BLOCK = this.create(
|
||||
name = "habitat_block",
|
||||
entry = HabitatBlock(
|
||||
properties = BlockBehaviour.Properties.of()
|
||||
.mapColor(MapColor.STONE)
|
||||
.strength(1.5F, Blocks.OBSIDIAN.explosionResistance)
|
||||
.pushReaction(PushReaction.BLOCK)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@JvmField
|
||||
val CAMPFIRE = create("campfire", CampfireBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOD).noOcclusion().pushReaction(PushReaction.BLOCK).mapColor(MapColor.PODZOL).strength(2.0F).lightLevel{14}, false))
|
||||
|
||||
@@ -603,7 +458,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
@JvmField
|
||||
val RELIC_COIN_POUCH = create("relic_coin_pouch", CoinPouchBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.RELIC_COIN_POUCH_SOUNDS).pushReaction(PushReaction.DESTROY).noOcclusion(), true))
|
||||
@JvmField
|
||||
val RELIC_COIN_SACK = create("relic_coin_sack", CoinPouchBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.RELIC_COIN_SACK_SOUNDS).pushReaction(PushReaction.DESTROY).strength(0.4F).mapColor(MapColor.GOLD), false))
|
||||
val RELIC_COIN_SACK = create("relic_coin_sack", CoinPouchBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.RELIC_COIN_SACK_SOUNDS).pushReaction(PushReaction.DESTROY).strength(0.4f), false))
|
||||
|
||||
@JvmField
|
||||
val GILDED_CHEST = create("gilded_chest", GildedChestBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.CHEST).noOcclusion().sound(CobblemonSounds.GILDED_CHEST_SOUNDS), GildedChestBlock.Type.RED))
|
||||
@@ -622,252 +477,32 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
@JvmField
|
||||
val GIMMIGHOUL_CHEST = create("gimmighoul_chest", GildedChestBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.CHEST).noOcclusion().sound(CobblemonSounds.GILDED_CHEST_SOUNDS), GildedChestBlock.Type.FAKE))
|
||||
|
||||
@JvmField
|
||||
val WHITE_PLAQUE = create("white_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
|
||||
@JvmField
|
||||
val LIGHT_GRAY_PLAQUE = create("light_gray_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
|
||||
@JvmField
|
||||
val GRAY_PLAQUE = create("gray_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
|
||||
@JvmField
|
||||
val BLACK_PLAQUE = create("black_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
|
||||
@JvmField
|
||||
val BROWN_PLAQUE = create("brown_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
|
||||
@JvmField
|
||||
val RED_PLAQUE = create("red_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
|
||||
@JvmField
|
||||
val ORANGE_PLAQUE = create("orange_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
|
||||
@JvmField
|
||||
val YELLOW_PLAQUE = create("yellow_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
|
||||
@JvmField
|
||||
val LIME_PLAQUE = create("lime_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
|
||||
@JvmField
|
||||
val GREEN_PLAQUE = create("green_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
|
||||
@JvmField
|
||||
val CYAN_PLAQUE = create("cyan_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
|
||||
@JvmField
|
||||
val LIGHT_BLUE_PLAQUE = create("light_blue_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
|
||||
@JvmField
|
||||
val BLUE_PLAQUE = create("blue_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
|
||||
@JvmField
|
||||
val PURPLE_PLAQUE = create("purple_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
|
||||
@JvmField
|
||||
val MAGENTA_PLAQUE = create("magenta_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
|
||||
@JvmField
|
||||
val PINK_PLAQUE = create("pink_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
|
||||
|
||||
@JvmField
|
||||
val CLEANSE_TAG = create("cleanse_tag", WallAttachedStackableItemBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.ITEM_BLOCK_PAPER_SMALL_SOUNDS).mapColor(MapColor.NONE).pushReaction(PushReaction.DESTROY).noOcclusion().noCollission(), WallAttachedStackableItemBlock.WallStackableItemBlockType.TAG))
|
||||
@JvmField
|
||||
val SPELL_TAG = create("spell_tag", WallAttachedStackableItemBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.ITEM_BLOCK_PAPER_SMALL_SOUNDS).mapColor(MapColor.NONE).pushReaction(PushReaction.DESTROY).noOcclusion().noCollission(), WallAttachedStackableItemBlock.WallStackableItemBlockType.TAG))
|
||||
|
||||
@JvmField
|
||||
val BLUNDER_POLICY = create("blunder_policy", WallAttachedDirectionalShapeBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.ITEM_BLOCK_PAPER_LARGE_SOUNDS).mapColor(MapColor.NONE).noOcclusion().noCollission(), 14, 12, 1))
|
||||
@JvmField
|
||||
val WEAKNESS_POLICY = create("weakness_policy", WallAttachedDirectionalShapeBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.ITEM_BLOCK_PAPER_LARGE_SOUNDS).mapColor(MapColor.NONE).noOcclusion().noCollission(), 14, 12, 1))
|
||||
|
||||
@JvmField
|
||||
val RING_TARGET = create("ring_target", RingTargetBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOD).mapColor(MapColor.NONE).noOcclusion().strength(0.125f)))
|
||||
@JvmField
|
||||
val MAGNET = create("magnet", MagnetBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.NONE).noOcclusion().strength(0.075f)))
|
||||
@JvmField
|
||||
val GALARICA_WREATH = create("galarica_wreath", GalaricaWreathBlock(BlockBehaviour.Properties.of().sound(SoundType.AZALEA_LEAVES).mapColor(MapColor.NONE).noOcclusion().noCollission()))
|
||||
|
||||
@JvmField
|
||||
val FLAME_ORB = create("flame_orb",OrbBlock(BlockBehaviour.Properties.of().sound(SoundType.GLASS).mapColor(MapColor.NONE).noOcclusion().lightLevel { 15 }))
|
||||
@JvmField
|
||||
val TOXIC_ORB = create("toxic_orb", OrbBlock(BlockBehaviour.Properties.of().sound(SoundType.GLASS).mapColor(MapColor.NONE).noOcclusion()))
|
||||
@JvmField
|
||||
val LIFE_ORB = create("life_orb", OrbBlock(BlockBehaviour.Properties.of().sound(SoundType.GLASS).mapColor(MapColor.NONE).noOcclusion().lightLevel{7}))
|
||||
@JvmField
|
||||
val LIGHT_BALL = create("light_ball", OrbBlock(BlockBehaviour.Properties.of().sound(SoundType.GLASS).mapColor(MapColor.NONE).noOcclusion().lightLevel{13}))
|
||||
@JvmField
|
||||
val SMOKE_BALL = create("smoke_ball", OrbBlock(BlockBehaviour.Properties.of().sound(SoundType.GLASS).mapColor(MapColor.NONE).noOcclusion()))
|
||||
|
||||
@JvmField
|
||||
val KINGS_ROCK = create("kings_rock", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.CENTERED_6x))
|
||||
|
||||
@JvmField
|
||||
val GALARICA_CUFF = create("galarica_cuff", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.AZALEA_LEAVES).mapColor(MapColor.NONE).noCollission().noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.FLATTENED_10x4))
|
||||
@JvmField
|
||||
val UNREMARKABLE_TEACUP = create("unremarkable_teacup", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DECORATED_POT).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.TEACUP))
|
||||
@JvmField
|
||||
val MASTERPIECE_TEACUP = create("masterpiece_teacup", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DECORATED_POT).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.TEACUP))
|
||||
@JvmField
|
||||
val CHIPPED_POT = create("chipped_pot", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DECORATED_POT).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.TEAPOT))
|
||||
@JvmField
|
||||
val CRACKED_POT = create("cracked_pot", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DECORATED_POT).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.TEAPOT))
|
||||
|
||||
@JvmField
|
||||
val SACHET = create("sachet", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOL).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.POUCH))
|
||||
@JvmField
|
||||
val METAL_POWDER = create("metal_powder", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOL).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.POUCH))
|
||||
@JvmField
|
||||
val QUICK_POWDER = create("quick_powder", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOL).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.POUCH))
|
||||
@JvmField
|
||||
val BRIGHT_POWDER = create("bright_powder", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOL).mapColor(MapColor.NONE).noOcclusion().lightLevel{3}, DecorativeItemBlock.DecorativeItemBlockType.POUCH))
|
||||
|
||||
@JvmField
|
||||
val NEVER_MELT_ICE = create("never_melt_ice", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.GLASS).mapColor(MapColor.NONE).noOcclusion().friction(0.989F), DecorativeItemBlock.DecorativeItemBlockType.NEVERMELT))
|
||||
@JvmField
|
||||
val SCOPE_LENS = create("scope_lens", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.COPPER).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.SCOPE))
|
||||
@JvmField
|
||||
val WIDE_LENS = create("wide_lens", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.COPPER).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.WIDE))
|
||||
@JvmField
|
||||
val ZOOM_LENS = create("zoom_lens", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.COPPER).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.ZOOM))
|
||||
|
||||
@JvmField
|
||||
val ICY_ROCK = create("icy_rock", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DEEPSLATE).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.FLATTENED_8x4))
|
||||
@JvmField
|
||||
val HEAT_ROCK = create("heat_rock", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DEEPSLATE).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.FLATTENED_8x4))
|
||||
@JvmField
|
||||
val SMOOTH_ROCK = create("smooth_rock", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DEEPSLATE).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.FLATTENED_8x4))
|
||||
@JvmField
|
||||
val DAMP_ROCK = create("damp_rock", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DEEPSLATE).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.FLATTENED_8x6))
|
||||
@JvmField
|
||||
val DESTINY_KNOT = create("destiny_knot", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOL).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.KNOT))
|
||||
@JvmField
|
||||
val LUMINOUS_MOSS = create("luminous_moss", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.MOSS).mapColor(MapColor.NONE).noOcclusion().lightLevel{5}, DecorativeItemBlock.DecorativeItemBlockType.CENTERED_8x))
|
||||
|
||||
@JvmField
|
||||
val METRONOME = create("metronome", ActivatableDecorationBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.NONE).pushReaction(PushReaction.DESTROY).noOcclusion(), ActivatableDecorationBlock.ActivatableDecorationBlockType.METRONOME))
|
||||
@JvmField
|
||||
val EJECT_BUTTON = create("eject_button", EjectButtonBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.NONE).pushReaction(PushReaction.DESTROY).noOcclusion().strength(0.125f), 40))
|
||||
|
||||
@JvmField
|
||||
val LOADED_DICE = create("loaded_dice", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.DICE))
|
||||
@JvmField
|
||||
val IRON_BALL = create("iron_ball", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.IRON_BALL))
|
||||
@JvmField
|
||||
val METAL_COAT = create("metal_coat", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.METAL_COAT))
|
||||
@JvmField
|
||||
val UPGRADE = create("upgrade", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.UPGRADE))
|
||||
@JvmField
|
||||
val DUBIOUS_DISC = create("dubious_disc", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.UPGRADE))
|
||||
|
||||
@JvmField
|
||||
val THROAT_SPRAY = create("throat_spray", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.THROAT_SPRAY))
|
||||
|
||||
@JvmField
|
||||
val FULL_HEAL = create("full_heal", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.STATUS_RESTORE))
|
||||
@JvmField
|
||||
val ANTIDOTE = create("antidote", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.STATUS_RESTORE))
|
||||
@JvmField
|
||||
val AWAKENING = create("awakening", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.STATUS_RESTORE))
|
||||
@JvmField
|
||||
val BURN_HEAL = create("burn_heal", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.STATUS_RESTORE))
|
||||
@JvmField
|
||||
val ICE_HEAL = create("ice_heal", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.STATUS_RESTORE))
|
||||
@JvmField
|
||||
val PARALYZE_HEAL = create("paralyze_heal", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.STATUS_RESTORE))
|
||||
|
||||
@JvmField
|
||||
val ETHER = create("ether", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.ETHER))
|
||||
@JvmField
|
||||
val MAX_ETHER = create("max_ether", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.ETHER))
|
||||
@JvmField
|
||||
val ELIXIR = create("elixir", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.ETHER))
|
||||
@JvmField
|
||||
val MAX_ELIXIR = create("max_elixir", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.ETHER))
|
||||
|
||||
@JvmField
|
||||
val POTION = create("potion", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.POTION))
|
||||
@JvmField
|
||||
val SUPER_POTION = create("super_potion", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.POTION))
|
||||
@JvmField
|
||||
val HYPER_POTION = create("hyper_potion", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.POTION))
|
||||
@JvmField
|
||||
val MAX_POTION = create("max_potion", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.MAX_POTION))
|
||||
@JvmField
|
||||
val FULL_RESTORE = create("full_restore", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.MAX_POTION))
|
||||
|
||||
@JvmField
|
||||
val DIRE_HIT = create("dire_hit", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.BATTLE_ITEM))
|
||||
@JvmField
|
||||
val GUARD_SPEC = create("guard_spec", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.BATTLE_ITEM))
|
||||
@JvmField
|
||||
val X_ACCURACY = create("x_${Stats.ACCURACY.identifier.path}", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.BATTLE_ITEM))
|
||||
@JvmField
|
||||
val X_ATTACK = create("x_${Stats.ATTACK.identifier.path}", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.BATTLE_ITEM))
|
||||
@JvmField
|
||||
val X_DEFENSE = create("x_${Stats.DEFENCE.identifier.path}", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.BATTLE_ITEM))
|
||||
@JvmField
|
||||
val X_SP_ATK = create("x_${Stats.SPECIAL_ATTACK.identifier.path}", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.BATTLE_ITEM))
|
||||
@JvmField
|
||||
val X_SP_DEF = create("x_${Stats.SPECIAL_DEFENCE.identifier.path}", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.BATTLE_ITEM))
|
||||
@JvmField
|
||||
val X_SPEED = create("x_${Stats.SPEED.identifier.path}", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.BATTLE_ITEM))
|
||||
|
||||
@JvmField
|
||||
val HP_UP = create("hp_up", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
|
||||
@JvmField
|
||||
val PROTEIN = create("protein", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
|
||||
@JvmField
|
||||
val IRON = create("iron", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
|
||||
@JvmField
|
||||
val CARBOS = create("carbos", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
|
||||
@JvmField
|
||||
val CALCIUM = create("calcium", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
|
||||
@JvmField
|
||||
val ZINC = create("zinc", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
|
||||
@JvmField
|
||||
val PP_UP = create("pp_up", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
|
||||
@JvmField
|
||||
val PP_MAX = create("pp_max", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.VITAMIN))
|
||||
|
||||
@JvmField
|
||||
val MONITOR = create("monitor", MonitorBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(5.0F, 6.0F).lightLevel { if (it.getValue(MonitorBlock.SCREEN) != MonitorBlock.MonitorScreen.OFF) 13 else 0 }))
|
||||
@JvmField
|
||||
val DAMAGED_MONITOR = create("damaged_monitor", DamagedMonitorBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(5.0F, 6.0F).lightLevel { when (it.getValue(DamagedMonitorBlock.SCREEN)) { DamagedMonitorBlock.BrokenMonitorScreen.GLITCHING -> 10; else -> 0 } }))
|
||||
@JvmField
|
||||
val FOSSIL_ANALYZER = create("fossil_analyzer", FossilAnalyzerBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(5.0F, 6.0F).noOcclusion()))
|
||||
@JvmField
|
||||
val RESTORATION_TANK = create("restoration_tank", RestorationTankBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.GLASS).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(5.0F, 6.0F).noOcclusion()))
|
||||
|
||||
@JvmField
|
||||
val HEALING_MACHINE = create("healing_machine", HealingMachineBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).strength(2F).noOcclusion().lightLevel { if (it.getValue(HealingMachineBlock.CHARGE_LEVEL) >= HealingMachineBlock.MAX_CHARGE_LEVEL) 12 else 5 }))
|
||||
val HEALING_MACHINE = create("healing_machine", HealingMachineBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).strength(2f).noOcclusion().lightLevel { if (it.getValue(HealingMachineBlock.CHARGE_LEVEL) >= HealingMachineBlock.MAX_CHARGE_LEVEL) 12 else 5 }))
|
||||
|
||||
@JvmField
|
||||
val PC = create("pc", PCBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).strength(2F).noOcclusion().lightLevel { if ((it.getValue(PCBlock.ON) as Boolean) && (it.getValue(PCBlock.PART) == PCBlock.PCPart.TOP)) 13 else 0 }))
|
||||
|
||||
@JvmField
|
||||
val TM_MACHINE = create(
|
||||
"tm_machine",
|
||||
TMMachineBlock(
|
||||
BlockBehaviour.Properties.of()
|
||||
.mapColor(MapColor.COLOR_GREEN)
|
||||
.sound(SoundType.METAL)
|
||||
.pushReaction(PushReaction.BLOCK)
|
||||
.strength(2F)
|
||||
.noOcclusion()
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@JvmField
|
||||
val LECTERN = create("lectern", LecternBlock(
|
||||
BlockBehaviour.Properties
|
||||
.of()
|
||||
.mapColor(MapColor.WOOD)
|
||||
.instrument(NoteBlockInstrument.BASS)
|
||||
.sound(SoundType.WOOD)
|
||||
.strength(2.5F)
|
||||
.ignitedByLava()
|
||||
.lightLevel { if (it.getValue(LecternBlock.EMIT_LIGHT) as Boolean) 13 else 0 }
|
||||
))
|
||||
|
||||
@JvmField
|
||||
val DISC_SHELF = create("disc_shelf", DiscShelfBlock(BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).sound(SoundType.METAL).strength(2.5F)))
|
||||
val LECTERN = create("lectern", LecternBlock(BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).sound(SoundType.WOOD).strength(2.5F).ignitedByLava().lightLevel { if (it.getValue(LecternBlock.EMIT_LIGHT) as Boolean) 13 else 0 }))
|
||||
|
||||
@JvmField
|
||||
val DISPLAY_CASE = create("display_case", DisplayCaseBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.DISPLAY_CASE_SOUNDS).noOcclusion().pushReaction(PushReaction.BLOCK).mapColor(MapColor.STONE).strength(0.3F).requiresCorrectToolForDrops()))
|
||||
|
||||
// TODO after 1.7
|
||||
// @JvmField
|
||||
// val INCENSE_SWEET = create("incense_sweet", SweetIncenseBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.DISPLAY_CASE_SOUNDS).noOcclusion().pushReaction(PushReaction.BLOCK).mapColor(MapColor.STONE).strength(0.3F)))
|
||||
// val INCENSE_SWEET = create("incense_sweet", SweetIncenseBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.DISPLAY_CASE_SOUNDS).noOcclusion().pushReaction(PushReaction.BLOCK).mapColor(MapColor.STONE).strength(0.3f)))
|
||||
|
||||
@JvmField
|
||||
val PASTURE = create("pasture", PastureBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BROWN).sound(SoundType.WOOD).strength(2F).noOcclusion().pushReaction(PushReaction.BLOCK).lightLevel { if ((it.getValue(PastureBlock.ON) as Boolean) && (it.getValue(PastureBlock.PART) == PastureBlock.PasturePart.TOP)) 13 else 0 }))
|
||||
@JvmField
|
||||
|
||||
val RED_MINT = create("red_mint", MintBlock(MintType.RED, BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_RED).noCollission().randomTicks().instabreak().sound(CobblemonSounds.MINT_SOUNDS).pushReaction(PushReaction.DESTROY)))
|
||||
@JvmField
|
||||
val BLUE_MINT = create("blue_mint", MintBlock(MintType.BLUE, BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLUE).noCollission().randomTicks().instabreak().sound(CobblemonSounds.MINT_SOUNDS).pushReaction(PushReaction.DESTROY)))
|
||||
@@ -931,9 +566,8 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
|
||||
private fun apricornBlock(name: String, apricorn: Apricorn): ApricornBlock = this.create(name, ApricornBlock(BlockBehaviour.Properties.of().mapColor(apricorn.mapColor()).randomTicks().strength(Blocks.OAK_LOG.defaultDestroyTime(), Blocks.OAK_LOG.explosionResistance).sound(SoundType.WOOD).noOcclusion(), apricorn))
|
||||
|
||||
private fun tumblestoneBlock(name: String, stage: Int, height: Int, xzOffset: Int, nextStage: Block?, mapColor: MapColor) : Block {
|
||||
private fun tumblestoneBlock(name: String, stage: Int, height: Int, xzOffset: Int, nextStage: Block?) : Block {
|
||||
return this.create(name, TumblestoneBlock(BlockBehaviour.Properties.of()
|
||||
.mapColor(mapColor)
|
||||
.pushReaction(PushReaction.DESTROY)
|
||||
.noOcclusion()
|
||||
.strength(1.5F)
|
||||
@@ -1085,91 +719,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
val YACHE_BERRY = this.berryBlock("yache")
|
||||
//val BINDING_SOIL = this.create("binding_soil", BindingSoilBlock(BlockBehaviour.Properties.of()))
|
||||
|
||||
val NEST_FIERY = this.create(
|
||||
"nest_fiery",
|
||||
WildNestBlock.create(
|
||||
WildNestType.FIERY,
|
||||
BlockBehaviour.Properties.of()
|
||||
.noOcclusion()
|
||||
.pushReaction(PushReaction.DESTROY)
|
||||
.lightLevel { state ->
|
||||
val variant = (state.block as? WildNestBlock)?.variantProperty?.let { state.getValue(it) }
|
||||
when (variant) {
|
||||
WildNestVariant.FIERY_NETHERRACK -> 15
|
||||
WildNestVariant.FIERY_SOUL_SAND -> 10
|
||||
else -> 3
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
val NEST_GRASSY = this.create(
|
||||
"nest_grassy",
|
||||
WildNestBlock.create(WildNestType.GRASSY, BlockBehaviour.Properties.of().noOcclusion().pushReaction(PushReaction.DESTROY))
|
||||
)
|
||||
val NEST_LEAFY = this.create(
|
||||
"nest_leafy",
|
||||
WildNestBlock.create(WildNestType.LEAFY, BlockBehaviour.Properties.of().noOcclusion().pushReaction(PushReaction.DESTROY))
|
||||
)
|
||||
val NEST_ICY = this.create(
|
||||
"nest_icy",
|
||||
WildNestBlock.create(WildNestType.ICY, BlockBehaviour.Properties.of().noOcclusion().pushReaction(PushReaction.DESTROY))
|
||||
)
|
||||
val NEST_HAY = this.create(
|
||||
"nest_hay",
|
||||
WildNestBlock.create(WildNestType.PLAYER, BlockBehaviour.Properties.of().noOcclusion().pushReaction(PushReaction.DESTROY))
|
||||
)
|
||||
val NEST_KELP = this.create(
|
||||
"nest_kelp",
|
||||
WildNestBlock.create(WildNestType.KELP, BlockBehaviour.Properties.of().noOcclusion().pushReaction(PushReaction.DESTROY))
|
||||
)
|
||||
val NEST_ROCKY = this.create(
|
||||
"nest_rocky",
|
||||
WildNestBlock.create(WildNestType.ROCKY, BlockBehaviour.Properties.of().noOcclusion().pushReaction(PushReaction.DESTROY))
|
||||
)
|
||||
val NEST_SANDY = this.create(
|
||||
"nest_sandy",
|
||||
WildNestBlock.create(WildNestType.SANDY, BlockBehaviour.Properties.of().noOcclusion().pushReaction(PushReaction.DESTROY))
|
||||
)
|
||||
val NEST_SHROOMY = this.create(
|
||||
"nest_shroomy",
|
||||
WildNestBlock.create(WildNestType.SHROOMY, BlockBehaviour.Properties.of().noOcclusion().pushReaction(PushReaction.DESTROY))
|
||||
)
|
||||
val NEST_TWIGGY = this.create(
|
||||
"nest_twiggy",
|
||||
WildNestBlock.create(WildNestType.TWIGGY, BlockBehaviour.Properties.of().noOcclusion().pushReaction(PushReaction.DESTROY))
|
||||
)
|
||||
val NEST_WATERY = this.create(
|
||||
"nest_watery",
|
||||
WildNestBlock.create(WildNestType.WATERY, BlockBehaviour.Properties.of().noOcclusion().pushReaction(PushReaction.DESTROY))
|
||||
)
|
||||
|
||||
val EGG = this.create("egg", EggBlock(BlockBehaviour.Properties
|
||||
.ofFullCopy(Blocks.DRAGON_EGG)
|
||||
.pushReaction(PushReaction.BLOCK)
|
||||
.sound(SoundType.BONE_BLOCK)
|
||||
))
|
||||
|
||||
@JvmField
|
||||
val INCUBATOR = this.create("incubator", IncubatorBlock(BlockBehaviour.Properties.of()
|
||||
.mapColor(MapColor.COLOR_LIGHT_GRAY)
|
||||
.sound(SoundType.METAL)
|
||||
.strength(Blocks.COAL_BLOCK.defaultDestroyTime(), Blocks.DIAMOND_ORE.explosionResistance)
|
||||
.noOcclusion()
|
||||
.pushReaction(PushReaction.BLOCK)
|
||||
.lightLevel { state ->
|
||||
if (state.getValue(IncubatorBlock.HAS_EGG) && !state.getValue(IncubatorBlock.READY)) 8 else 0 // emit light only when warming the egg
|
||||
}
|
||||
))
|
||||
|
||||
@JvmField
|
||||
val SCAREKROW = this.create("scarekrow", ScarekrowBlock(
|
||||
BlockBehaviour.Properties.of()
|
||||
.pushReaction(PushReaction.DESTROY)
|
||||
.sound(SoundType.GRASS)
|
||||
.strength(0.1f)
|
||||
.noOcclusion()
|
||||
))
|
||||
|
||||
init {
|
||||
/**
|
||||
* Makes all blocks in array flammable by adding them to FireBlock's flammableRegistry.
|
||||
@@ -1210,12 +759,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
return block
|
||||
}
|
||||
|
||||
private fun nestBlock(variant: NestBlock.NestVariant): NestBlock {
|
||||
val identifier = cobblemonResource(variant.serializedName)
|
||||
val block = NestBlock(variant, BlockBehaviour.Properties.of().noOcclusion().pushReaction(PushReaction.DESTROY))
|
||||
return this.create(identifier.path, block)
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls helper method from Vanilla
|
||||
*/
|
||||
@@ -1253,28 +796,4 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
val block = BlocksInvoker.createLeavesBlock(SoundType.GRASS)
|
||||
return this.create(name, block)
|
||||
}
|
||||
|
||||
private fun typeGemBlock(name: String, mapColor: MapColor): Block {
|
||||
val typeGemBlock = this.create(name, Block(BlockBehaviour.Properties.of().mapColor(mapColor).strength(3.0F, 6.0F).sound(CobblemonSounds.TYPE_GEM_BLOCK_SOUNDS)))
|
||||
|
||||
val identifier = cobblemonResource(name)
|
||||
typeGemBlocks[identifier] = typeGemBlock
|
||||
|
||||
return typeGemBlock
|
||||
}
|
||||
|
||||
fun typeGemBlocks() = typeGemBlocks.toMap()
|
||||
|
||||
private fun typeGemCluster(name: String, gemBlock: Block, dropItemId: ResourceLocation, mapColor: MapColor): Block {
|
||||
val gemClusterBlock = this.create(name, TypeGemClusterBlock(BlockBehaviour.Properties.of().mapColor(mapColor).strength(2.0F, 3.0F).sound(CobblemonSounds.TYPE_GEM_CLUSTER_SOUNDS).pushReaction(PushReaction.DESTROY), gemBlock, dropItemId))
|
||||
|
||||
TypeGemClusterBlock.gemToClusterMap[gemBlock] = gemClusterBlock
|
||||
|
||||
val identifier = cobblemonResource(name)
|
||||
typeGemClusters[identifier] = gemClusterBlock
|
||||
|
||||
return gemClusterBlock
|
||||
}
|
||||
|
||||
fun typeGemClusters() = typeGemClusters.toMap()
|
||||
}
|
||||
}
|
||||
@@ -61,8 +61,6 @@ object CobblemonCommands {
|
||||
ChangeBoxWallpaperCommand.register(dispatcher)
|
||||
RunMolangCommand.register(dispatcher)
|
||||
RunMolangScriptCommand.register(dispatcher)
|
||||
GivePokemonEggCommand.register(dispatcher)
|
||||
GiveAllPokemonEggCommand.register(dispatcher)
|
||||
SpectateBattleCommand.register(dispatcher)
|
||||
CobblemonConfigCommand.register(dispatcher)
|
||||
UnlockPCBoxWallpaperCommand.register(dispatcher)
|
||||
@@ -73,13 +71,10 @@ object CobblemonCommands {
|
||||
MarkGiveAllCommand.register(dispatcher)
|
||||
PcSearchCommand.register(dispatcher)
|
||||
PcTakeCommand.register(dispatcher)
|
||||
GiveTmCommand.register(dispatcher)
|
||||
TmCommand.register(dispatcher)
|
||||
BreedPokemonCommand.register(dispatcher)
|
||||
|
||||
// Possibly lock down registration if and only if under dev environment or running in an environment
|
||||
// with a certain system environment variable set
|
||||
CobblemonInfoCommand.register(dispatcher)
|
||||
DebugCobblemonAICommand.register(dispatcher)
|
||||
CalculateSeatPositionCommand.register(dispatcher)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,8 +26,6 @@ import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.resources.ResourceKey
|
||||
import net.minecraft.world.entity.MobCategory
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeSupplier
|
||||
import com.cobblemon.mod.common.entity.RealtimeMoveProjectile
|
||||
import com.example.mod.entity.RealtimeMoveAreaEffect
|
||||
|
||||
object CobblemonEntities : PlatformRegistry<Registry<EntityType<*>>, ResourceKey<Registry<EntityType<*>>>, EntityType<*>>() {
|
||||
|
||||
@@ -89,25 +87,6 @@ object CobblemonEntities : PlatformRegistry<Registry<EntityType<*>>, ResourceKey
|
||||
.build(GENERIC_BEDROCK_ENTITY_KEY.toString())
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val REALTIME_MOVE_PROJECTILE_ENTITY_KEY = cobblemonResource("realtime_move_projectile")
|
||||
@JvmField
|
||||
val REALTIME_MOVE_PROJECTILE_ENTITY: EntityType<RealtimeMoveProjectile> = this.create(
|
||||
REALTIME_MOVE_PROJECTILE_ENTITY_KEY.path,
|
||||
EntityType.Builder.of({ _, world -> RealtimeMoveProjectile(world) }, MobCategory.MISC)
|
||||
.build(REALTIME_MOVE_PROJECTILE_ENTITY_KEY.toString())
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val REALTIME_MOVE_PROJECTILE_AOE_KEY = cobblemonResource("realtime_move_aoe")
|
||||
@JvmField
|
||||
val REALTIME_MOVE_PROJECTILE_AOE: EntityType<RealtimeMoveAreaEffect> = this.create(
|
||||
REALTIME_MOVE_PROJECTILE_AOE_KEY.path,
|
||||
EntityType.Builder.of({ _, world -> RealtimeMoveAreaEffect(world) }, MobCategory.MISC)
|
||||
.build(REALTIME_MOVE_PROJECTILE_AOE_KEY.toString())
|
||||
)
|
||||
|
||||
|
||||
@JvmField
|
||||
val NPC_KEY = cobblemonResource("npc")
|
||||
@JvmField
|
||||
|
||||
@@ -12,7 +12,6 @@ import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.mojang.brigadier.arguments.ArgumentType
|
||||
import kotlin.reflect.KClass
|
||||
import net.minecraft.commands.synchronization.ArgumentTypeInfo
|
||||
import net.minecraft.core.HolderLookup
|
||||
import net.minecraft.resources.ResourceKey
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.MinecraftServer
|
||||
@@ -20,7 +19,6 @@ import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
import net.minecraft.server.packs.resources.PreparableReloadListener
|
||||
import net.minecraft.tags.TagKey
|
||||
import net.minecraft.world.inventory.MenuType
|
||||
import net.minecraft.world.level.GameRules
|
||||
import net.minecraft.world.level.ItemLike
|
||||
import net.minecraft.world.level.biome.Biome
|
||||
@@ -169,16 +167,12 @@ interface CobblemonImplementation {
|
||||
* TODO
|
||||
*
|
||||
* @param identifier
|
||||
* @param reloaderFactory
|
||||
* @param reloader
|
||||
* @param type
|
||||
* @param dependencies
|
||||
*/
|
||||
fun registerResourceReloader(
|
||||
identifier: ResourceLocation,
|
||||
type: PackType,
|
||||
dependencies: Collection<ResourceLocation>,
|
||||
reloaderFactory: (HolderLookup.Provider) -> PreparableReloadListener
|
||||
)
|
||||
fun registerResourceReloader(identifier: ResourceLocation, reloader: PreparableReloadListener, type: PackType, dependencies: Collection<ResourceLocation>)
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
|
||||
@@ -18,7 +18,6 @@ import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.network.codec.ByteBufCodecs
|
||||
import net.minecraft.resources.ResourceKey
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.ExtraCodecs
|
||||
|
||||
object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>, ResourceKey<Registry<DataComponentType<*>>>, DataComponentType<*>>() {
|
||||
|
||||
@@ -69,22 +68,6 @@ object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>
|
||||
.persistent(FoodColourComponent.CODEC)
|
||||
.networkSynchronized(FoodColourComponent.PACKET_CODEC)
|
||||
.build())
|
||||
@JvmField
|
||||
val EGG_DATA: DataComponentType<EggComponent> = create("egg", DataComponentType.builder<EggComponent>()
|
||||
.persistent(EggComponent.CODEC) // For saving/loading
|
||||
.networkSynchronized(EggComponent.PACKET_CODEC) // For network synchronization
|
||||
.build())
|
||||
@JvmField
|
||||
val EGG_MODEL: DataComponentType<String> = create("egg_model", DataComponentType.builder<String>()
|
||||
.persistent(ExtraCodecs.NON_EMPTY_STRING)
|
||||
.networkSynchronized(ByteBufCodecs.STRING_UTF8)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val TM_MOVE: DataComponentType<TMMoveComponent> = create("tm_move", DataComponentType.builder<TMMoveComponent>()
|
||||
.persistent(TMMoveComponent.CODEC)
|
||||
.networkSynchronized(TMMoveComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val INGREDIENT: DataComponentType<IngredientComponent> = create("ingredient", DataComponentType.builder<IngredientComponent>()
|
||||
@@ -118,12 +101,9 @@ object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:flavour"), FLAVOUR)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:ride_boosts"), RIDE_BOOST)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:food_colour"), FOOD_COLOUR)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:tm_move"), TM_MOVE)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:ingredient"), INGREDIENT)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:food"), FOOD)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:mob_effects"), MOB_EFFECTS)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:egg_data"), EGG_DATA)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:egg_model"), EGG_MODEL)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:held_item_effect"), HELD_ITEM_EFFECT)
|
||||
}
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ import com.cobblemon.mod.common.api.text.gray
|
||||
import com.cobblemon.mod.common.block.BerryBlock
|
||||
import com.cobblemon.mod.common.block.MintBlock
|
||||
import com.cobblemon.mod.common.block.MintBlock.MintType
|
||||
import com.cobblemon.mod.common.block.campfirepot.CampfirePotColor
|
||||
import com.cobblemon.mod.common.client.pokedex.PokedexType
|
||||
import com.cobblemon.mod.common.block.campfirepot.CampfirePotColor
|
||||
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
|
||||
import com.cobblemon.mod.common.item.*
|
||||
import com.cobblemon.mod.common.item.armor.CobblemonArmorTrims
|
||||
@@ -35,6 +35,7 @@ import com.cobblemon.mod.common.item.berry.HealingBerryItem
|
||||
import com.cobblemon.mod.common.item.berry.PPRestoringBerryItem
|
||||
import com.cobblemon.mod.common.item.berry.PortionHealingBerryItem
|
||||
import com.cobblemon.mod.common.item.berry.StatusCuringBerryItem
|
||||
import com.cobblemon.mod.common.item.interactive.PonigiriItem
|
||||
import com.cobblemon.mod.common.item.food.SinisterTeaItem
|
||||
import com.cobblemon.mod.common.item.interactive.*
|
||||
import com.cobblemon.mod.common.item.interactive.ability.AbilityChangeItem
|
||||
@@ -205,8 +206,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_WHITE = campfirePotItem(CobblemonBlocks.WHITE_CAMPFIRE_POT, CampfirePotColor.WHITE)
|
||||
|
||||
@JvmField
|
||||
val SCAREKROW = blockItem("scarekrow", CobblemonBlocks.SCAREKROW)
|
||||
@JvmField
|
||||
val HEARTY_GRAINS = compostableItem("hearty_grains", ItemNameBlockItem(CobblemonBlocks.HEARTY_GRAINS, Properties().rarity(Rarity.COMMON)))
|
||||
@JvmField
|
||||
@@ -407,7 +406,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val BIG_MALASADA = regionalFoodItem("big_malasada", 64, 7, 0.3f, false)
|
||||
@JvmField
|
||||
val SMOKED_TAIL_CURRY = regionalFoodItem("smoked_tail_curry", 64, 10, 0.6f, false)
|
||||
val SMOKED_TAIL_CURRY = regionalFoodItem("smoked_tail_curry", 64, 10, 0.6f, false, ItemStack(Items.BOWL, 1))
|
||||
@JvmField
|
||||
val JUBILIFE_MUFFIN = regionalFoodItem("jubilife_muffin", 64, 7, 0.3f, false)
|
||||
@JvmField
|
||||
@@ -454,16 +453,10 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val MONITOR = blockItem("monitor", CobblemonBlocks.MONITOR)
|
||||
@JvmField
|
||||
val DAMAGED_MONITOR = blockItem("damaged_monitor", CobblemonBlocks.DAMAGED_MONITOR)
|
||||
@JvmField
|
||||
val HEALING_MACHINE = blockItem("healing_machine", CobblemonBlocks.HEALING_MACHINE, Rarity.UNCOMMON)
|
||||
@JvmField
|
||||
val PC = blockItem("pc", CobblemonBlocks.PC)
|
||||
@JvmField
|
||||
val TM_MACHINE = blockItem("tm_machine", CobblemonBlocks.TM_MACHINE)
|
||||
@JvmField
|
||||
val DISC_SHELF = blockItem("disc_shelf", CobblemonBlocks.DISC_SHELF)
|
||||
@JvmField
|
||||
val PASTURE = blockItem("pasture", CobblemonBlocks.PASTURE)
|
||||
@JvmField
|
||||
val DISPLAY_CASE = blockItem("display_case", CobblemonBlocks.DISPLAY_CASE)
|
||||
@@ -474,9 +467,9 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
// Evolution items
|
||||
@JvmField val LINK_CABLE = create("link_cable", LinkCableItem())
|
||||
@JvmField val DRAGON_SCALE = noSettingsItem("dragon_scale")
|
||||
@JvmField val METAL_COAT = itemNameBlockItem("metal_coat", CobblemonBlocks.METAL_COAT)
|
||||
@JvmField val UPGRADE = itemNameBlockItem("upgrade", CobblemonBlocks.UPGRADE)
|
||||
@JvmField val DUBIOUS_DISC = itemNameBlockItem("dubious_disc", CobblemonBlocks.DUBIOUS_DISC)
|
||||
@JvmField val METAL_COAT = noSettingsItem("metal_coat")
|
||||
@JvmField val UPGRADE = noSettingsItem("upgrade")
|
||||
@JvmField val DUBIOUS_DISC = noSettingsItem("dubious_disc")
|
||||
@JvmField val DEEP_SEA_SCALE = noSettingsItem("deep_sea_scale")
|
||||
@JvmField val DEEP_SEA_TOOTH = noSettingsItem("deep_sea_tooth")
|
||||
@JvmField val ELECTIRIZER = noSettingsItem("electirizer")
|
||||
@@ -485,7 +478,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField val PROTECTOR = noSettingsItem("protector")
|
||||
@JvmField val REAPER_CLOTH = noSettingsItem("reaper_cloth")
|
||||
@JvmField val PRISM_SCALE = noSettingsItem("prism_scale")
|
||||
@JvmField val SACHET = itemNameBlockItem("sachet", CobblemonBlocks.SACHET)
|
||||
@JvmField val SACHET = noSettingsItem("sachet")
|
||||
@JvmField val WHIPPED_DREAM = create("whipped_dream", foodItem(8, 0.3f))
|
||||
@JvmField val STRAWBERRY_SWEET = create("strawberry_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val LOVE_SWEET = create("love_sweet", foodItem(6, 0.125f))
|
||||
@@ -494,41 +487,26 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField val FLOWER_SWEET = create("flower_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val STAR_SWEET = create("star_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val RIBBON_SWEET = create("ribbon_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val CHIPPED_POT = itemNameBlockItem("chipped_pot", CobblemonBlocks.CHIPPED_POT)
|
||||
@JvmField val CRACKED_POT = itemNameBlockItem("cracked_pot", CobblemonBlocks.CRACKED_POT)
|
||||
@JvmField val MASTERPIECE_TEACUP = itemNameBlockItem("masterpiece_teacup", CobblemonBlocks.MASTERPIECE_TEACUP)
|
||||
@JvmField val UNREMARKABLE_TEACUP = itemNameBlockItem("unremarkable_teacup", CobblemonBlocks.UNREMARKABLE_TEACUP)
|
||||
@JvmField val CHIPPED_POT = noSettingsItem("chipped_pot")
|
||||
@JvmField val CRACKED_POT = noSettingsItem("cracked_pot")
|
||||
@JvmField val MASTERPIECE_TEACUP = noSettingsItem("masterpiece_teacup")
|
||||
@JvmField val UNREMARKABLE_TEACUP = noSettingsItem("unremarkable_teacup")
|
||||
@JvmField val SWEET_APPLE = compostableItem("sweet_apple", foodItem(4, 0.3f), 0.65f)
|
||||
@JvmField val TART_APPLE = compostableItem("tart_apple", foodItem(4, 0.3f), 0.65f)
|
||||
@JvmField val SYRUPY_APPLE = compostableItem("syrupy_apple", foodItem(4, 0.3f), 0.65f)
|
||||
@JvmField val GALARICA_CUFF = itemNameBlockItem("galarica_cuff", CobblemonBlocks.GALARICA_CUFF)
|
||||
@JvmField val GALARICA_CUFF = noSettingsItem("galarica_cuff")
|
||||
@JvmField val GALARICA_WREATH = noSettingsItem("galarica_wreath")
|
||||
@JvmField val BLACK_AUGURITE = noSettingsItem("black_augurite")
|
||||
@JvmField val PEAT_BLOCK = noSettingsItem("peat_block")
|
||||
@JvmField val RAZOR_CLAW = noSettingsItem("razor_claw")
|
||||
@JvmField val RAZOR_FANG = noSettingsItem("razor_fang")
|
||||
@JvmField val AUSPICIOUS_ARMOR = heldItem("auspicious_armor")
|
||||
@JvmField val MALICIOUS_ARMOR = heldItem("malicious_armor")
|
||||
@JvmField val SHELL_HELMET = heldItem("shell_helmet")
|
||||
@JvmField val METAL_ALLOY = noSettingsItem("metal_alloy")
|
||||
@JvmField val SCROLL_OF_DARKNESS = noSettingsItem("scroll_of_darkness")
|
||||
@JvmField val SCROLL_OF_WATERS = noSettingsItem("scroll_of_waters")
|
||||
|
||||
@JvmField val WHITE_PLAQUE = blockItem("white_plaque", CobblemonBlocks.WHITE_PLAQUE)
|
||||
@JvmField val LIGHT_GRAY_PLAQUE = blockItem("light_gray_plaque", CobblemonBlocks.LIGHT_GRAY_PLAQUE)
|
||||
@JvmField val GRAY_PLAQUE = blockItem("gray_plaque", CobblemonBlocks.GRAY_PLAQUE)
|
||||
@JvmField val BLACK_PLAQUE = blockItem("black_plaque", CobblemonBlocks.BLACK_PLAQUE)
|
||||
@JvmField val BROWN_PLAQUE = blockItem("brown_plaque", CobblemonBlocks.BROWN_PLAQUE)
|
||||
@JvmField val RED_PLAQUE = blockItem("red_plaque", CobblemonBlocks.RED_PLAQUE)
|
||||
@JvmField val ORANGE_PLAQUE = blockItem("orange_plaque", CobblemonBlocks.ORANGE_PLAQUE)
|
||||
@JvmField val YELLOW_PLAQUE = blockItem("yellow_plaque", CobblemonBlocks.YELLOW_PLAQUE)
|
||||
@JvmField val LIME_PLAQUE = blockItem("lime_plaque", CobblemonBlocks.LIME_PLAQUE)
|
||||
@JvmField val GREEN_PLAQUE = blockItem("green_plaque", CobblemonBlocks.GREEN_PLAQUE)
|
||||
@JvmField val CYAN_PLAQUE = blockItem("cyan_plaque", CobblemonBlocks.CYAN_PLAQUE)
|
||||
@JvmField val LIGHT_BLUE_PLAQUE = blockItem("light_blue_plaque", CobblemonBlocks.LIGHT_BLUE_PLAQUE)
|
||||
@JvmField val BLUE_PLAQUE = blockItem("blue_plaque", CobblemonBlocks.BLUE_PLAQUE)
|
||||
@JvmField val PURPLE_PLAQUE = blockItem("purple_plaque", CobblemonBlocks.PURPLE_PLAQUE)
|
||||
@JvmField val MAGENTA_PLAQUE = blockItem("magenta_plaque", CobblemonBlocks.MAGENTA_PLAQUE)
|
||||
@JvmField val PINK_PLAQUE = blockItem("pink_plaque", CobblemonBlocks.PINK_PLAQUE)
|
||||
|
||||
private val berries = mutableMapOf<ResourceLocation, BerryItem>()
|
||||
// Plants
|
||||
@JvmField val CHERI_BERRY = berryItem("cheri", StatusCuringBerryItem(CobblemonBlocks.CHERI_BERRY, Statuses.PARALYSIS))
|
||||
@@ -604,25 +582,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
|
||||
@JvmField val BERRY_JUICE = this.create("berry_juice", BerryJuiceItem())
|
||||
|
||||
val NEST_GRASSY = blockItem("nest_grassy", CobblemonBlocks.NEST_GRASSY)
|
||||
val NEST_LEAFY = blockItem("nest_leafy", CobblemonBlocks.NEST_LEAFY)
|
||||
val NEST_FIERY = blockItem("nest_fiery", CobblemonBlocks.NEST_FIERY)
|
||||
val NEST_ICY = blockItem("nest_icy", CobblemonBlocks.NEST_ICY)
|
||||
val NEST_HAY = blockItem("nest_hay", CobblemonBlocks.NEST_HAY)
|
||||
val NEST_KELP = blockItem("nest_kelp", CobblemonBlocks.NEST_KELP)
|
||||
val NEST_ROCKY = blockItem("nest_rocky", CobblemonBlocks.NEST_ROCKY)
|
||||
val NEST_SANDY = blockItem("nest_sandy", CobblemonBlocks.NEST_SANDY)
|
||||
val NEST_SHROOMY = blockItem("nest_shroomy", CobblemonBlocks.NEST_SHROOMY)
|
||||
val NEST_TWIGGY = blockItem("nest_twiggy", CobblemonBlocks.NEST_TWIGGY)
|
||||
val NEST_WATERY = blockItem("nest_watery", CobblemonBlocks.NEST_WATERY)
|
||||
|
||||
|
||||
@JvmField
|
||||
val INCUBATOR = blockItem("incubator", CobblemonBlocks.INCUBATOR)
|
||||
|
||||
@JvmField
|
||||
val HABITAT_BLOCK = blockItem("habitat_block", CobblemonBlocks.HABITAT_BLOCK)
|
||||
|
||||
@JvmField
|
||||
val GALARICA_NUTS = compostableItemNameBlockItem("galarica_nuts", CobblemonBlocks.GALARICA_NUT_BUSH)
|
||||
|
||||
@@ -667,17 +626,17 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val EXPERIENCE_CANDY_XL = candyItem("exp_candy_xl") { _, _ -> CandyItem.DEFAULT_XL_CANDY_YIELD }
|
||||
@JvmField
|
||||
val CALCIUM = create("calcium", VitaminItem(Stats.SPECIAL_ATTACK, CobblemonBlocks.CALCIUM))
|
||||
val CALCIUM = create("calcium", VitaminItem(Stats.SPECIAL_ATTACK))
|
||||
@JvmField
|
||||
val CARBOS = create("carbos", VitaminItem(Stats.SPEED, CobblemonBlocks.CARBOS))
|
||||
val CARBOS = create("carbos", VitaminItem(Stats.SPEED))
|
||||
@JvmField
|
||||
val HP_UP = create("hp_up", VitaminItem(Stats.HP, CobblemonBlocks.HP_UP))
|
||||
val HP_UP = create("hp_up", VitaminItem(Stats.HP))
|
||||
@JvmField
|
||||
val IRON = create("iron", VitaminItem(Stats.DEFENCE, CobblemonBlocks.IRON))
|
||||
val IRON = create("iron", VitaminItem(Stats.DEFENCE))
|
||||
@JvmField
|
||||
val PROTEIN = create("protein", VitaminItem(Stats.ATTACK, CobblemonBlocks.PROTEIN))
|
||||
val PROTEIN = create("protein", VitaminItem(Stats.ATTACK))
|
||||
@JvmField
|
||||
val ZINC = create("zinc", VitaminItem(Stats.SPECIAL_DEFENCE, CobblemonBlocks.ZINC))
|
||||
val ZINC = create("zinc", VitaminItem(Stats.SPECIAL_DEFENCE))
|
||||
@JvmField
|
||||
val HEALTH_MOCHI = create("health_mochi", MochiItem(Stats.HP))
|
||||
@JvmField
|
||||
@@ -740,15 +699,15 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
val MOOMOO_MILK = create("moomoo_milk", MoomooMilk(Item.Properties().craftRemainder(Items.GLASS_BOTTLE).stacksTo((16))))
|
||||
|
||||
@JvmField
|
||||
val POTION = create("potion", PotionItem(PotionType.POTION, CobblemonBlocks.POTION))
|
||||
val POTION = create("potion", PotionItem(PotionType.POTION))
|
||||
@JvmField
|
||||
val SUPER_POTION = create("super_potion", PotionItem(PotionType.SUPER_POTION, CobblemonBlocks.SUPER_POTION))
|
||||
val SUPER_POTION = create("super_potion", PotionItem(PotionType.SUPER_POTION))
|
||||
@JvmField
|
||||
val HYPER_POTION = create("hyper_potion", PotionItem(PotionType.HYPER_POTION, CobblemonBlocks.HYPER_POTION))
|
||||
val HYPER_POTION = create("hyper_potion", PotionItem(PotionType.HYPER_POTION))
|
||||
@JvmField
|
||||
val MAX_POTION = create("max_potion", PotionItem(PotionType.MAX_POTION, CobblemonBlocks.MAX_POTION))
|
||||
val MAX_POTION = create("max_potion", PotionItem(PotionType.MAX_POTION))
|
||||
@JvmField
|
||||
val FULL_RESTORE = create("full_restore", PotionItem(PotionType.FULL_RESTORE, CobblemonBlocks.FULL_RESTORE))
|
||||
val FULL_RESTORE = create("full_restore", PotionItem(PotionType.FULL_RESTORE))
|
||||
|
||||
@JvmField
|
||||
val HEAL_POWDER = create("heal_powder", HealPowderItem())
|
||||
@@ -759,9 +718,9 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val MAX_REVIVE = create("max_revive", ReviveItem(max = true))
|
||||
@JvmField
|
||||
val PP_UP = create("pp_up", PPUpItem(1, CobblemonBlocks.PP_UP))
|
||||
val PP_UP = create("pp_up", PPUpItem(1))
|
||||
@JvmField
|
||||
val PP_MAX = create("pp_max", PPUpItem(3, CobblemonBlocks.PP_MAX))
|
||||
val PP_MAX = create("pp_max", PPUpItem(3))
|
||||
|
||||
@JvmField
|
||||
val RED_MINT_SEEDS = mintSeed("red", MintType.RED.getCropBlock())
|
||||
@@ -833,27 +792,28 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val SERIOUS_MINT = mintItem("serious_mint", MintItem(Natures.SERIOUS))
|
||||
|
||||
@JvmField val X_ACCURACY = create("x_${Stats.ACCURACY.identifier.path}", XStatItem(Stats.ACCURACY, block = CobblemonBlocks.X_ACCURACY))
|
||||
@JvmField val X_ATTACK = create("x_${Stats.ATTACK.identifier.path}", XStatItem(Stats.ATTACK, block = CobblemonBlocks.X_ATTACK))
|
||||
@JvmField val X_DEFENSE = create("x_${Stats.DEFENCE.identifier.path}", XStatItem(Stats.DEFENCE, block = CobblemonBlocks.X_DEFENSE))
|
||||
@JvmField val X_SP_ATK = create("x_${Stats.SPECIAL_ATTACK.identifier.path}", XStatItem(Stats.SPECIAL_ATTACK, block = CobblemonBlocks.X_SP_ATK))
|
||||
@JvmField val X_SP_DEF = create("x_${Stats.SPECIAL_DEFENCE.identifier.path}", XStatItem(Stats.SPECIAL_DEFENCE, block = CobblemonBlocks.X_SP_DEF))
|
||||
@JvmField val X_SPEED = create("x_${Stats.SPEED.identifier.path}", XStatItem(Stats.SPEED, block = CobblemonBlocks.X_SPEED))
|
||||
@JvmField val X_ACCURACY = create("x_${Stats.ACCURACY.identifier.path}", XStatItem(Stats.ACCURACY))
|
||||
@JvmField val X_ATTACK = create("x_${Stats.ATTACK.identifier.path}", XStatItem(Stats.ATTACK))
|
||||
@JvmField val X_DEFENSE = create("x_${Stats.DEFENCE.identifier.path}", XStatItem(Stats.DEFENCE))
|
||||
@JvmField val X_SP_ATK = create("x_${Stats.SPECIAL_ATTACK.identifier.path}", XStatItem(Stats.SPECIAL_ATTACK))
|
||||
@JvmField val X_SP_DEF = create("x_${Stats.SPECIAL_DEFENCE.identifier.path}", XStatItem(Stats.SPECIAL_DEFENCE))
|
||||
@JvmField val X_SPEED = create("x_${Stats.SPEED.identifier.path}", XStatItem(Stats.SPEED))
|
||||
|
||||
@JvmField val DIRE_HIT = create("dire_hit", DireHitItem(CobblemonBlocks.DIRE_HIT))
|
||||
@JvmField val GUARD_SPEC = create("guard_spec", GuardSpecItem(CobblemonBlocks.GUARD_SPEC))
|
||||
@JvmField val DIRE_HIT = create("dire_hit", DireHitItem())
|
||||
@JvmField val GUARD_SPEC = create("guard_spec", GuardSpecItem())
|
||||
|
||||
@JvmField val FULL_HEAL = create("full_heal", StatusCureItem("item.cobblemon.full_heal", *Statuses.getPersistentStatuses().toTypedArray(), block = CobblemonBlocks.FULL_HEAL))
|
||||
@JvmField val ANTIDOTE = create("antidote", StatusCureItem("item.cobblemon.antidote", Statuses.POISON, Statuses.POISON_BADLY, block = CobblemonBlocks.ANTIDOTE))
|
||||
@JvmField val AWAKENING = create("awakening", StatusCureItem("item.cobblemon.awakening", Statuses.SLEEP, block = CobblemonBlocks.AWAKENING))
|
||||
@JvmField val BURN_HEAL = create("burn_heal", StatusCureItem("item.cobblemon.burn_heal", Statuses.BURN, block = CobblemonBlocks.BURN_HEAL))
|
||||
@JvmField val ICE_HEAL = create("ice_heal", StatusCureItem("item.cobblemon.ice_heal", Statuses.FROZEN, block = CobblemonBlocks.ICE_HEAL))
|
||||
@JvmField val PARALYZE_HEAL = create("paralyze_heal", StatusCureItem("item.cobblemon.paralyze_heal", Statuses.PARALYSIS, block = CobblemonBlocks.PARALYZE_HEAL))
|
||||
@JvmField val BURN_HEAL = create("burn_heal", StatusCureItem("item.cobblemon.burn_heal", Statuses.BURN))
|
||||
@JvmField val PARALYZE_HEAL = create("paralyze_heal", StatusCureItem("item.cobblemon.paralyze_heal", Statuses.PARALYSIS))
|
||||
@JvmField val ICE_HEAL = create("ice_heal", StatusCureItem("item.cobblemon.ice_heal", Statuses.FROZEN))
|
||||
@JvmField val ANTIDOTE = create("antidote", StatusCureItem("item.cobblemon.antidote", Statuses.POISON, Statuses.POISON_BADLY))
|
||||
@JvmField val AWAKENING = create("awakening", StatusCureItem("item.cobblemon.awakening", Statuses.SLEEP))
|
||||
|
||||
@JvmField val ETHER = create("ether", EtherItem(max = false, CobblemonBlocks.ETHER))
|
||||
@JvmField val MAX_ETHER = create("max_ether", EtherItem(max = true, CobblemonBlocks.MAX_ETHER))
|
||||
@JvmField val ELIXIR = create("elixir", ElixirItem(max = false, CobblemonBlocks.ELIXIR))
|
||||
@JvmField val MAX_ELIXIR = create("max_elixir", ElixirItem(max = true, CobblemonBlocks.MAX_ELIXIR))
|
||||
@JvmField val FULL_HEAL = create("full_heal", StatusCureItem("item.cobblemon.full_heal"))
|
||||
|
||||
@JvmField val ETHER = create("ether", EtherItem(max = false))
|
||||
@JvmField val MAX_ETHER = create("max_ether", EtherItem(max = true))
|
||||
@JvmField val ELIXIR = create("elixir", ElixirItem(max = false))
|
||||
@JvmField val MAX_ELIXIR = create("max_elixir", ElixirItem(max = true))
|
||||
|
||||
@JvmField
|
||||
val ABILITY_CAPSULE = this.create("ability_capsule", AbilityChangeItem(AbilityChanger.COMMON_ABILITY))
|
||||
@@ -938,18 +898,11 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField val CHOICE_SPECS = wearableItem("choice_specs")
|
||||
@JvmField val EXP_SHARE = wearableItem("exp_share")
|
||||
@JvmField val FOCUS_BAND = wearableItem("focus_band")
|
||||
@JvmField val KINGS_ROCK = wearableBlockItem("kings_rock", CobblemonBlocks.KINGS_ROCK)
|
||||
@JvmField val NEVER_MELT_ICE = wearableBlockItem("never_melt_ice", CobblemonBlocks.NEVER_MELT_ICE)
|
||||
@JvmField val KINGS_ROCK = wearableItem("kings_rock")
|
||||
@JvmField val MUSCLE_BAND = wearableItem("muscle_band")
|
||||
@JvmField val ROCKY_HELMET = wearableItem("rocky_helmet")
|
||||
@JvmField val SAFETY_GOGGLES = wearableItem("safety_goggles")
|
||||
@JvmField val WISE_GLASSES = wearableItem("wise_glasses")
|
||||
@JvmField val SHARP_BEAK = wearableItem("sharp_beak")
|
||||
@JvmField val COVERT_CLOAK = wearableItem("covert_cloak")
|
||||
@JvmField val SHELL_HELMET = wearableItem("shell_helmet")
|
||||
@JvmField val GALARICA_WREATH = wearableBlockItem("galarica_wreath", CobblemonBlocks.GALARICA_WREATH)
|
||||
@JvmField val CLEANSE_TAG = wearableBlockItem("cleanse_tag", CobblemonBlocks.CLEANSE_TAG)
|
||||
@JvmField val SPELL_TAG = wearableBlockItem("spell_tag", CobblemonBlocks.SPELL_TAG)
|
||||
|
||||
// Held Items
|
||||
@JvmField
|
||||
@@ -969,7 +922,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val BLACK_SLUDGE = heldItem("black_sludge")
|
||||
@JvmField
|
||||
val BLUNDER_POLICY = itemNameBlockItem("blunder_policy", CobblemonBlocks.BLUNDER_POLICY)
|
||||
val BLUNDER_POLICY = heldItem("blunder_policy")
|
||||
@JvmField
|
||||
val CELL_BATTERY = heldItem("cell_battery")
|
||||
@JvmField
|
||||
@@ -977,13 +930,17 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val CHOICE_SCARF = heldItem("choice_scarf")
|
||||
@JvmField
|
||||
val CLEANSE_TAG = heldItem("cleanse_tag")
|
||||
@JvmField
|
||||
val CLEAR_AMULET = heldItem("clear_amulet")
|
||||
@JvmField
|
||||
val DESTINY_KNOT = create("destiny_knot", ItemNameBlockItem(CobblemonBlocks.DESTINY_KNOT, Item.Properties().durability(256)))
|
||||
val COVERT_CLOAK = heldItem("covert_cloak")
|
||||
@JvmField
|
||||
val DESTINY_KNOT = heldItem("destiny_knot")
|
||||
@JvmField
|
||||
val DRAGON_FANG = heldItem("dragon_fang")
|
||||
@JvmField
|
||||
val EJECT_BUTTON = itemNameBlockItem("eject_button", CobblemonBlocks.EJECT_BUTTON)
|
||||
val EJECT_BUTTON = heldItem("eject_button")
|
||||
@JvmField
|
||||
val EJECT_PACK = heldItem("eject_pack")
|
||||
@JvmField
|
||||
@@ -997,7 +954,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val FAIRY_FEATHER = heldItem("fairy_feather")
|
||||
@JvmField
|
||||
val FLAME_ORB = itemNameBlockItem("flame_orb", CobblemonBlocks.FLAME_ORB)
|
||||
val FLAME_ORB = heldItem("flame_orb")
|
||||
@JvmField
|
||||
val FLOAT_STONE = heldItem("float_stone")
|
||||
@JvmField
|
||||
@@ -1011,32 +968,34 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val HEAVY_DUTY_BOOTS = heldItem("heavy_duty_boots")
|
||||
@JvmField
|
||||
val IRON_BALL = itemNameBlockItem("iron_ball", CobblemonBlocks.IRON_BALL)
|
||||
val IRON_BALL = heldItem("iron_ball")
|
||||
@JvmField
|
||||
val LAGGING_TAIL = heldItem("lagging_tail")
|
||||
@JvmField
|
||||
val LEFTOVERS = compostableHeldItem("leftovers", null, 0.50f)
|
||||
@JvmField
|
||||
val LIFE_ORB = itemNameBlockItem("life_orb", CobblemonBlocks.LIFE_ORB)
|
||||
val LIFE_ORB = heldItem("life_orb")
|
||||
@JvmField
|
||||
val LIGHT_BALL = itemNameBlockItem("light_ball", CobblemonBlocks.LIGHT_BALL)
|
||||
val LIGHT_BALL = heldItem("light_ball")
|
||||
@JvmField
|
||||
val LIGHT_CLAY = heldItem("light_clay")
|
||||
@JvmField
|
||||
val LOADED_DICE = itemNameBlockItem("loaded_dice", CobblemonBlocks.LOADED_DICE)
|
||||
val LOADED_DICE = heldItem("loaded_dice")
|
||||
@JvmField
|
||||
val LUCKY_EGG = heldItem("lucky_egg")
|
||||
@JvmField
|
||||
val LUMINOUS_MOSS = itemNameBlockItem("luminous_moss", CobblemonBlocks.LUMINOUS_MOSS)
|
||||
val LUMINOUS_MOSS = heldItem("luminous_moss")
|
||||
@JvmField
|
||||
val MAGNET = itemNameBlockItem("magnet", CobblemonBlocks.MAGNET)
|
||||
val MAGNET = heldItem("magnet")
|
||||
@JvmField
|
||||
val METRONOME = itemNameBlockItem("metronome", CobblemonBlocks.METRONOME)
|
||||
val METRONOME = heldItem("metronome")
|
||||
@JvmField
|
||||
val MIRACLE_SEED = heldItem("miracle_seed")
|
||||
@JvmField
|
||||
val MYSTIC_WATER = heldItem("mystic_water")
|
||||
@JvmField
|
||||
val NEVER_MELT_ICE = heldItem("never_melt_ice")
|
||||
@JvmField
|
||||
val POISON_BARB = heldItem("poison_barb")
|
||||
@JvmField
|
||||
val POWER_ANKLET = heldItem("power_anklet")
|
||||
@@ -1061,11 +1020,13 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val RED_CARD = heldItem("red_card")
|
||||
@JvmField
|
||||
val RING_TARGET = itemNameBlockItem("ring_target", CobblemonBlocks.RING_TARGET)
|
||||
val RING_TARGET = heldItem("ring_target")
|
||||
@JvmField
|
||||
val ROOM_SERVICE = heldItem("room_service")
|
||||
@JvmField
|
||||
val SCOPE_LENS = itemNameBlockItem("scope_lens", CobblemonBlocks.SCOPE_LENS)
|
||||
val SCOPE_LENS = heldItem("scope_lens")
|
||||
@JvmField
|
||||
val SHARP_BEAK = heldItem("sharp_beak")
|
||||
@JvmField
|
||||
val SHED_SHELL = heldItem("shed_shell")
|
||||
@JvmField
|
||||
@@ -1077,7 +1038,9 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val SOFT_SAND = heldItem("soft_sand")
|
||||
@JvmField
|
||||
val SMOKE_BALL = itemNameBlockItem("smoke_ball", CobblemonBlocks.SMOKE_BALL)
|
||||
val SPELL_TAG = heldItem("spell_tag")
|
||||
@JvmField
|
||||
val SMOKE_BALL = heldItem("smoke_ball")
|
||||
@JvmField
|
||||
val SOOTHE_BELL = heldItem("soothe_bell")
|
||||
@JvmField
|
||||
@@ -1085,19 +1048,19 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val TERRAIN_EXTENDER = heldItem("terrain_extender")
|
||||
@JvmField
|
||||
val THROAT_SPRAY = itemNameBlockItem("throat_spray", CobblemonBlocks.THROAT_SPRAY)
|
||||
val THROAT_SPRAY = heldItem("throat_spray")
|
||||
@JvmField
|
||||
val TOXIC_ORB = itemNameBlockItem("toxic_orb", CobblemonBlocks.TOXIC_ORB)
|
||||
val TOXIC_ORB = heldItem("toxic_orb")
|
||||
@JvmField
|
||||
val TWISTED_SPOON = heldItem("twisted_spoon")
|
||||
@JvmField
|
||||
val UTILITY_UMBRELLA = heldItem("utility_umbrella")
|
||||
@JvmField
|
||||
val WEAKNESS_POLICY = itemNameBlockItem("weakness_policy", CobblemonBlocks.WEAKNESS_POLICY)
|
||||
val WEAKNESS_POLICY = heldItem("weakness_policy")
|
||||
@JvmField
|
||||
val WIDE_LENS = itemNameBlockItem("wide_lens", CobblemonBlocks.WIDE_LENS)
|
||||
val WIDE_LENS = heldItem("wide_lens")
|
||||
@JvmField
|
||||
val ZOOM_LENS = itemNameBlockItem("zoom_lens", CobblemonBlocks.ZOOM_LENS)
|
||||
val ZOOM_LENS = heldItem("zoom_lens")
|
||||
@JvmField
|
||||
val MENTAL_HERB = compostableHeldItem("mental_herb", null, 0.85F)
|
||||
@JvmField
|
||||
@@ -1109,19 +1072,19 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val WHITE_HERB = compostableHeldItem("white_herb", null, 0.85F)
|
||||
@JvmField
|
||||
val BRIGHT_POWDER = itemNameBlockItem("bright_powder", CobblemonBlocks.BRIGHT_POWDER)
|
||||
val BRIGHT_POWDER = heldItem("bright_powder")
|
||||
@JvmField
|
||||
val METAL_POWDER = itemNameBlockItem("metal_powder", CobblemonBlocks.METAL_POWDER)
|
||||
val METAL_POWDER = heldItem("metal_powder")
|
||||
@JvmField
|
||||
val QUICK_POWDER = itemNameBlockItem("quick_powder", CobblemonBlocks.QUICK_POWDER)
|
||||
val QUICK_POWDER = heldItem("quick_powder")
|
||||
@JvmField
|
||||
val DAMP_ROCK = itemNameBlockItem("damp_rock", CobblemonBlocks.DAMP_ROCK)
|
||||
val DAMP_ROCK = heldItem("damp_rock")
|
||||
@JvmField
|
||||
val HEAT_ROCK = itemNameBlockItem("heat_rock", CobblemonBlocks.HEAT_ROCK)
|
||||
val HEAT_ROCK = heldItem("heat_rock")
|
||||
@JvmField
|
||||
val SMOOTH_ROCK = itemNameBlockItem("smooth_rock", CobblemonBlocks.SMOOTH_ROCK)
|
||||
val SMOOTH_ROCK = heldItem("smooth_rock")
|
||||
@JvmField
|
||||
val ICY_ROCK = itemNameBlockItem("icy_rock", CobblemonBlocks.ICY_ROCK)
|
||||
val ICY_ROCK = heldItem("icy_rock")
|
||||
|
||||
// Mulch
|
||||
@JvmField
|
||||
@@ -1229,83 +1192,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val BLACK_TUMBLESTONE_BLOCK = blockItem("black_tumblestone_block", CobblemonBlocks.BLACK_TUMBLESTONE_BLOCK)
|
||||
|
||||
@JvmField
|
||||
val TYPE_GEM_CORE = blockItem("deepslate_crystal_core", CobblemonBlocks.TYPE_GEM_CORE)
|
||||
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_NORMAL = blockItem("normal_gem_cluster", CobblemonBlocks.TYPE_GEM_CLUSTER_NORMAL)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_FIRE = blockItem("fire_gem_cluster", CobblemonBlocks.TYPE_GEM_CLUSTER_FIRE)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_WATER = blockItem("water_gem_cluster", CobblemonBlocks.TYPE_GEM_CLUSTER_WATER)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_ELECTRIC = blockItem("electric_gem_cluster", CobblemonBlocks.TYPE_GEM_CLUSTER_ELECTRIC)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_GRASS = blockItem("grass_gem_cluster", CobblemonBlocks.TYPE_GEM_CLUSTER_GRASS)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_ICE = blockItem("ice_gem_cluster", CobblemonBlocks.TYPE_GEM_CLUSTER_ICE)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_FIGHTING = blockItem("fighting_gem_cluster", CobblemonBlocks.TYPE_GEM_CLUSTER_FIGHTING)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_POISON = blockItem("poison_gem_cluster", CobblemonBlocks.TYPE_GEM_CLUSTER_POISON)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_GROUND = blockItem("ground_gem_cluster", CobblemonBlocks.TYPE_GEM_CLUSTER_GROUND)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_FLYING = blockItem("flying_gem_cluster", CobblemonBlocks.TYPE_GEM_CLUSTER_FLYING)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_PSYCHIC = blockItem("psychic_gem_cluster", CobblemonBlocks.TYPE_GEM_CLUSTER_PSYCHIC)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_BUG = blockItem("bug_gem_cluster", CobblemonBlocks.TYPE_GEM_CLUSTER_BUG)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_ROCK = blockItem("rock_gem_cluster", CobblemonBlocks.TYPE_GEM_CLUSTER_ROCK)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_GHOST = blockItem("ghost_gem_cluster", CobblemonBlocks.TYPE_GEM_CLUSTER_GHOST)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_DRAGON = blockItem("dragon_gem_cluster", CobblemonBlocks.TYPE_GEM_CLUSTER_DRAGON)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_DARK = blockItem("dark_gem_cluster", CobblemonBlocks.TYPE_GEM_CLUSTER_DARK)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_STEEL = blockItem("steel_gem_cluster", CobblemonBlocks.TYPE_GEM_CLUSTER_STEEL)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_FAIRY = blockItem("fairy_gem_cluster", CobblemonBlocks.TYPE_GEM_CLUSTER_FAIRY)
|
||||
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_NORMAL = blockItem("normal_gem_block", CobblemonBlocks.TYPE_GEM_BLOCK_NORMAL)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_FIRE = blockItem("fire_gem_block", CobblemonBlocks.TYPE_GEM_BLOCK_FIRE)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_WATER = blockItem("water_gem_block", CobblemonBlocks.TYPE_GEM_BLOCK_WATER)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_ELECTRIC = blockItem("electric_gem_block", CobblemonBlocks.TYPE_GEM_BLOCK_ELECTRIC)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_GRASS = blockItem("grass_gem_block", CobblemonBlocks.TYPE_GEM_BLOCK_GRASS)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_ICE = blockItem("ice_gem_block", CobblemonBlocks.TYPE_GEM_BLOCK_ICE)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_FIGHTING = blockItem("fighting_gem_block", CobblemonBlocks.TYPE_GEM_BLOCK_FIGHTING)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_POISON = blockItem("poison_gem_block", CobblemonBlocks.TYPE_GEM_BLOCK_POISON)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_GROUND = blockItem("ground_gem_block", CobblemonBlocks.TYPE_GEM_BLOCK_GROUND)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_FLYING = blockItem("flying_gem_block", CobblemonBlocks.TYPE_GEM_BLOCK_FLYING)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_PSYCHIC = blockItem("psychic_gem_block", CobblemonBlocks.TYPE_GEM_BLOCK_PSYCHIC)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_BUG = blockItem("bug_gem_block", CobblemonBlocks.TYPE_GEM_BLOCK_BUG)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_ROCK = blockItem("rock_gem_block", CobblemonBlocks.TYPE_GEM_BLOCK_ROCK)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_GHOST = blockItem("ghost_gem_block", CobblemonBlocks.TYPE_GEM_BLOCK_GHOST)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_DRAGON = blockItem("dragon_gem_block", CobblemonBlocks.TYPE_GEM_BLOCK_DRAGON)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_DARK = blockItem("dark_gem_block", CobblemonBlocks.TYPE_GEM_BLOCK_DARK)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_STEEL = blockItem("steel_gem_block", CobblemonBlocks.TYPE_GEM_BLOCK_STEEL)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_FAIRY = blockItem("fairy_gem_block", CobblemonBlocks.TYPE_GEM_BLOCK_FAIRY)
|
||||
|
||||
@JvmField
|
||||
val POKEROD_SMITHING_TEMPLATE = create("pokerod_smithing_template", SmithingTemplateItem(
|
||||
Component.translatable("item.minecraft.fishing_rod").blue(),
|
||||
@@ -1530,55 +1416,46 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
val RELIC_COIN_POUCH = blockItem("relic_coin_pouch", CobblemonBlocks.RELIC_COIN_POUCH)
|
||||
@JvmField
|
||||
val RELIC_COIN_SACK = blockItem("relic_coin_sack", CobblemonBlocks.RELIC_COIN_SACK)
|
||||
@JvmField
|
||||
val TECHNICAL_MACHINE = this.create("technical_machine", TechnicalMachineItem(Properties()))
|
||||
@JvmField
|
||||
val BLANK_TM = this.create("blank_tm", CobblemonItem(Item.Properties()))
|
||||
|
||||
// Type Gems
|
||||
@JvmField
|
||||
val NORMAL_GEM = this.create("normal_gem", GemItem(Item.Properties(), CobblemonBlocks.TYPE_GEM_CLUSTER_NORMAL))
|
||||
val NORMAL_GEM = noSettingsItem("normal_gem")
|
||||
@JvmField
|
||||
val FIRE_GEM = this.create("fire_gem", GemItem(Item.Properties(), CobblemonBlocks.TYPE_GEM_CLUSTER_FIRE))
|
||||
val FIRE_GEM = noSettingsItem("fire_gem")
|
||||
@JvmField
|
||||
val WATER_GEM = this.create("water_gem", GemItem(Item.Properties(), CobblemonBlocks.TYPE_GEM_CLUSTER_WATER))
|
||||
val WATER_GEM = noSettingsItem("water_gem")
|
||||
@JvmField
|
||||
val GRASS_GEM = this.create("grass_gem", GemItem(Item.Properties(), CobblemonBlocks.TYPE_GEM_CLUSTER_GRASS))
|
||||
val GRASS_GEM = noSettingsItem("grass_gem")
|
||||
@JvmField
|
||||
val ELECTRIC_GEM = this.create("electric_gem", GemItem(Item.Properties(), CobblemonBlocks.TYPE_GEM_CLUSTER_ELECTRIC))
|
||||
val ELECTRIC_GEM = noSettingsItem("electric_gem")
|
||||
@JvmField
|
||||
val ICE_GEM = this.create("ice_gem", GemItem(Item.Properties(), CobblemonBlocks.TYPE_GEM_CLUSTER_ICE))
|
||||
val ICE_GEM = noSettingsItem("ice_gem")
|
||||
@JvmField
|
||||
val FIGHTING_GEM = this.create("fighting_gem", GemItem(Item.Properties(), CobblemonBlocks.TYPE_GEM_CLUSTER_FIGHTING))
|
||||
val FIGHTING_GEM = noSettingsItem("fighting_gem")
|
||||
@JvmField
|
||||
val POISON_GEM = this.create("poison_gem", GemItem(Item.Properties(), CobblemonBlocks.TYPE_GEM_CLUSTER_POISON))
|
||||
val POISON_GEM = noSettingsItem("poison_gem")
|
||||
@JvmField
|
||||
val GROUND_GEM = this.create("ground_gem", GemItem(Item.Properties(), CobblemonBlocks.TYPE_GEM_CLUSTER_GROUND))
|
||||
val GROUND_GEM = noSettingsItem("ground_gem")
|
||||
@JvmField
|
||||
val FLYING_GEM = this.create("flying_gem", GemItem(Item.Properties(), CobblemonBlocks.TYPE_GEM_CLUSTER_FLYING))
|
||||
val FLYING_GEM = noSettingsItem("flying_gem")
|
||||
@JvmField
|
||||
val PSYCHIC_GEM = this.create("psychic_gem", GemItem(Item.Properties(), CobblemonBlocks.TYPE_GEM_CLUSTER_PSYCHIC))
|
||||
val PSYCHIC_GEM = noSettingsItem("psychic_gem")
|
||||
@JvmField
|
||||
val BUG_GEM = this.create("bug_gem", GemItem(Item.Properties(), CobblemonBlocks.TYPE_GEM_CLUSTER_BUG))
|
||||
val BUG_GEM = noSettingsItem("bug_gem")
|
||||
@JvmField
|
||||
val ROCK_GEM = this.create("rock_gem", GemItem(Item.Properties(), CobblemonBlocks.TYPE_GEM_CLUSTER_ROCK))
|
||||
val ROCK_GEM = noSettingsItem("rock_gem")
|
||||
@JvmField
|
||||
val GHOST_GEM = this.create("ghost_gem", GemItem(Item.Properties(), CobblemonBlocks.TYPE_GEM_CLUSTER_GHOST))
|
||||
val GHOST_GEM = noSettingsItem("ghost_gem")
|
||||
@JvmField
|
||||
val DRAGON_GEM = this.create("dragon_gem", GemItem(Item.Properties(), CobblemonBlocks.TYPE_GEM_CLUSTER_DRAGON))
|
||||
val DRAGON_GEM = noSettingsItem("dragon_gem")
|
||||
@JvmField
|
||||
val DARK_GEM = this.create("dark_gem", GemItem(Item.Properties(), CobblemonBlocks.TYPE_GEM_CLUSTER_DARK))
|
||||
val DARK_GEM = noSettingsItem("dark_gem")
|
||||
@JvmField
|
||||
val STEEL_GEM = this.create("steel_gem", GemItem(Item.Properties(), CobblemonBlocks.TYPE_GEM_CLUSTER_STEEL))
|
||||
val STEEL_GEM = noSettingsItem("steel_gem")
|
||||
@JvmField
|
||||
val FAIRY_GEM = this.create("fairy_gem", GemItem(Item.Properties(), CobblemonBlocks.TYPE_GEM_CLUSTER_FAIRY))
|
||||
|
||||
val FAIRY_GEM = noSettingsItem("fairy_gem")
|
||||
//@JvmField
|
||||
//val BINDING_SOIL = blockItem("binding_soil", CobblemonBlocks.BINDING_SOIL)
|
||||
@JvmField
|
||||
val POKEMON_EGG = eggItem("egg", CobblemonBlocks.EGG, Item.Properties().stacksTo(1))
|
||||
|
||||
private fun eggItem(name: String, block: Block, settings: Item.Properties = Item.Properties()): BlockItem = this.create(name, BlockItem(block, settings))
|
||||
|
||||
private fun blockItem(name: String, block: Block, rarity: Rarity = Rarity.COMMON): BlockItem = this.create(name, BlockItem(block, Item.Properties().rarity(rarity)))
|
||||
|
||||
@@ -1616,16 +1493,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
|
||||
private fun wearableItem(name: String, heldItemRemappedName: String? = null): CobblemonItem = create(
|
||||
name,
|
||||
WearableHatItem(name).also {
|
||||
wearables.add(it)
|
||||
if (heldItemRemappedName != null) {
|
||||
CobblemonHeldItemManager.registerRemap(it, heldItemRemappedName)
|
||||
}
|
||||
}
|
||||
)
|
||||
private fun wearableBlockItem(name: String, block: Block, heldItemRemappedName: String? = null): WearableBlockItem = create(
|
||||
name,
|
||||
WearableBlockItem(name, block).also {
|
||||
WearableItem(name).also {
|
||||
wearables.add(it)
|
||||
if (heldItemRemappedName != null) {
|
||||
CobblemonHeldItemManager.registerRemap(it, heldItemRemappedName)
|
||||
@@ -1677,15 +1545,14 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
return create(name, RegionalFoodItem(properties))
|
||||
}
|
||||
|
||||
private fun heldItem(name: String, remappedName: String? = null, settings:Item.Properties = Item.Properties()): CobblemonItem = create(
|
||||
private fun heldItem(name: String, remappedName: String? = null): CobblemonItem = create(
|
||||
name,
|
||||
CobblemonItem(settings).also {
|
||||
CobblemonItem(Item.Properties()).also {
|
||||
if (remappedName != null) {
|
||||
CobblemonHeldItemManager.registerRemap(it, remappedName)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
private fun heldItem(name: String, item: Item, remappedName: String? = null) = create(
|
||||
name = name,
|
||||
entry = item.also {
|
||||
|
||||
@@ -12,17 +12,15 @@ import com.cobblemon.mod.common.api.ai.CobblemonAttackTargetData
|
||||
import com.cobblemon.mod.common.api.ai.CobblemonWanderControl
|
||||
import com.cobblemon.mod.common.api.dialogue.ActiveDialogue
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.ListCodec
|
||||
import com.mojang.serialization.codecs.PrimitiveCodec
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.GlobalPos
|
||||
import net.minecraft.core.UUIDUtil
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import java.util.*
|
||||
|
||||
object CobblemonMemories {
|
||||
val memories = mutableMapOf<String, MemoryModuleType<*>>()
|
||||
@@ -41,14 +39,6 @@ object CobblemonMemories {
|
||||
@JvmField
|
||||
val ACTIVE_ACTION_EFFECT = register<ActionEffectContext>("active_action_effect")
|
||||
@JvmField
|
||||
val POTENTIAL_MATE = register<PokemonEntity>("potential_mate")
|
||||
@JvmField
|
||||
val MATE_SCAN_COOLDOWN = register("mate_scan_cooldown", PrimitiveCodec.BOOL)
|
||||
@JvmField
|
||||
val NEST_LOCATION = register<BlockPos>("nest_location")
|
||||
@JvmField
|
||||
val PATERNAL_NEST_LOCATION = register<BlockPos>("paternal_nest", BlockPos.CODEC)
|
||||
@JvmField
|
||||
val POKEMON_FLYING = register("pokemon_flying", PrimitiveCodec.BOOL)
|
||||
@JvmField
|
||||
val POKEMON_DROWSY = register("pokemon_drowsy", PrimitiveCodec.BOOL)
|
||||
@@ -65,28 +55,16 @@ object CobblemonMemories {
|
||||
@JvmField
|
||||
val NEARBY_GROWABLE_CROPS = register<BlockPos>("nearby_growable_crops")
|
||||
@JvmField
|
||||
val EGG_THIEF = register<Player>("egg_thief") // Stores the player stealing the egg
|
||||
@JvmField
|
||||
val EGG_THIEF_LAST_SEEN_TICK = register("egg_thief_last_seen_tick", PrimitiveCodec.LONG)
|
||||
@JvmField
|
||||
val EGG_LOCATION = register<BlockPos>("egg_location") // Stores the last known location of the egg
|
||||
@JvmField
|
||||
val EGG_IN_NEST = register("egg_in_nest", PrimitiveCodec.BOOL)
|
||||
@JvmField
|
||||
val HOLDING_EGG = register("holding_egg", PrimitiveCodec.BOOL)
|
||||
@JvmField
|
||||
val EGG_SEARCH_COUNTDOWN = register ("egg_search_countdown", PrimitiveCodec.BOOL)
|
||||
@JvmField
|
||||
val IDEAL_NEST_LOCATION = register<BlockPos>("ideal_nest_location")
|
||||
@JvmField
|
||||
val NEST_DESPAWN_IMMUNE_UNTIL_TICK = register("nest_despawn_immune_until_tick", PrimitiveCodec.LONG)
|
||||
@JvmField
|
||||
val NEARBY_SWEET_BERRY_BUSH = register<BlockPos>("nearest_sweet_berry_bush")
|
||||
@JvmField
|
||||
val DISABLE_WALK_TO_BERRY_BUSH = register<Boolean>("disable_walk_to_berry_bush")
|
||||
@JvmField
|
||||
val TIME_TRYING_TO_REACH_BERRY_BUSH = register<Int>("time_trying_to_reach_berry_bush")
|
||||
@JvmField
|
||||
val IS_CONSUMING_ITEM = register<Boolean>("is_consuming_item")
|
||||
@JvmField
|
||||
val RECENTLY_ATE_GRASS = register<Boolean>("recently_ate_grass")
|
||||
@JvmField
|
||||
val HIVE_LOCATION = register<BlockPos>("hive_location", BlockPos.CODEC)
|
||||
@JvmField
|
||||
val HIVE_BLACKLIST = register<List<BlockPos>>("hive_blacklist")
|
||||
@@ -114,8 +92,6 @@ object CobblemonMemories {
|
||||
val DISABLE_WALK_TO_WANTED_ITEM = register<Boolean>("disable_walk_to_wanted_item")
|
||||
@JvmField
|
||||
val TIME_TRYING_TO_REACH_WANTED_ITEM = register<Int>("time_trying_to_wanted_item")
|
||||
@JvmField
|
||||
val NEARBY_SCAREKROW = register<BlockPos>("nearby_scarekrow", BlockPos.CODEC)
|
||||
|
||||
@JvmStatic
|
||||
fun <U> register(id: String, codec: Codec<U>): MemoryModuleType<U> {
|
||||
@@ -130,4 +106,4 @@ object CobblemonMemories {
|
||||
memories[id] = memoryModule
|
||||
return memoryModule
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common
|
||||
|
||||
|
||||
import com.cobblemon.mod.common.block.campfirepot.CookingPotMenu
|
||||
import com.cobblemon.mod.common.block.tmmachine.TMMachineMenu
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import net.minecraft.core.Registry
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
@@ -20,8 +19,7 @@ import net.minecraft.world.inventory.MenuType
|
||||
|
||||
object CobblemonMenuType : PlatformRegistry<Registry<MenuType<*>>, ResourceKey<Registry<MenuType<*>>>, MenuType<*>>() {
|
||||
|
||||
val COOKING_POT = MenuType.register("cooking_pot_menu", ::CookingPotMenu)
|
||||
val TM_MACHINE = MenuType.register("tm_machine_menu", ::TMMachineMenu)
|
||||
val COOKING_POT = MenuType.register("cooking_pot", ::CookingPotMenu)
|
||||
|
||||
override val registry: Registry<MenuType<*>>
|
||||
get() = BuiltInRegistries.MENU
|
||||
|
||||
@@ -1,55 +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.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.moves.MoveSelector
|
||||
import com.cobblemon.mod.common.api.moves.MovesetBuilder
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.MovesetBuilderAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.StringToObjectAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
|
||||
object CobblemonMovesetBuilders : JsonDataRegistry<MovesetBuilder> {
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
|
||||
.registerTypeAdapter(MovesetBuilder::class.java, MovesetBuilderAdapter)
|
||||
.registerTypeAdapter(MoveSelector::class.java, StringToObjectAdapter(MoveSelector.selectors))
|
||||
.create()
|
||||
|
||||
override val typeToken = TypeToken.get(MovesetBuilder::class.java)
|
||||
override val resourcePath = "moveset_builders"
|
||||
override val id: ResourceLocation = cobblemonResource("moveset_builders")
|
||||
override val type = PackType.SERVER_DATA
|
||||
override val observable = SimpleObservable<CobblemonMovesetBuilders>()
|
||||
|
||||
val movesetBuilders = mutableMapOf<ResourceLocation, MovesetBuilder>()
|
||||
|
||||
fun getOrThrow(id: ResourceLocation): MovesetBuilder {
|
||||
return movesetBuilders[id]
|
||||
?: throw IllegalArgumentException("Unknown MovesetBuilder id: $id")
|
||||
}
|
||||
|
||||
override fun sync(player: ServerPlayer) { /* These don't sync. But what if they did? Nah probably shouldn't sync. */ }
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, MovesetBuilder>) {
|
||||
movesetBuilders.clear()
|
||||
data.forEach { (id, value) -> value.id = id }
|
||||
movesetBuilders.putAll(data)
|
||||
observable.emit(this)
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.client.net.CalculateSeatPositionsHandler
|
||||
import com.cobblemon.mod.common.client.net.OpenBehaviourEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.PlayerInteractOptionsHandler
|
||||
import com.cobblemon.mod.common.client.net.SetClientPlayerDataHandler
|
||||
@@ -20,34 +21,21 @@ import com.cobblemon.mod.common.client.net.callback.partymove.OpenPartyMoveCallb
|
||||
import com.cobblemon.mod.common.client.net.cooking.ToggleCookingPotLidHandler
|
||||
import com.cobblemon.mod.common.client.net.data.CobblemonMechanicsSyncHandler
|
||||
import com.cobblemon.mod.common.client.net.data.DataRegistrySyncPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.data.PokemonInteractionsSyncHandler
|
||||
import com.cobblemon.mod.common.client.net.data.RideSettingsSyncHandler
|
||||
import com.cobblemon.mod.common.client.net.debug.OpenRidingStatsDebugGUIHandler
|
||||
import com.cobblemon.mod.common.client.net.debug.UpdateTrackedBrainDataHandler
|
||||
import com.cobblemon.mod.common.client.net.dialogue.DialogueClosedHandler
|
||||
import com.cobblemon.mod.common.client.net.dialogue.DialogueOpenedHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.PokeSnackBlockParticlesHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.RunPosableMoLangHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.SaccharineLogBlockParticlesHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormEntityParticleHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormParticleHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.*
|
||||
import com.cobblemon.mod.common.client.net.gui.ExpGainedDataPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.InteractPokemonUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.PokedexUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.SetActiveTMPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.SetTMMachineContainerDataPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.SynchronizeActiveTMHandler
|
||||
import com.cobblemon.mod.common.client.net.habitat.OpenHabitatBlockEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.npc.CloseNPCEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.npc.OpenNPCEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.orientation.ClientboundUpdateOrientationHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.ClosePastureHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.OpenPastureHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.PokemonPasturedHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.PokemonUnpasturedHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.UpdatePastureConflictFlagHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.*
|
||||
import com.cobblemon.mod.common.client.net.pokedex.ServerConfirmedRegisterHandler
|
||||
import com.cobblemon.mod.common.client.net.pokemon.update.ClientboundSeatAssignmentPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.pokemon.update.ClientboundUpdateRidingStateHandler
|
||||
import com.cobblemon.mod.common.client.net.pokemon.update.PokemonUpdatePacketHandler
|
||||
import com.cobblemon.mod.common.client.net.riding.ClientboundUpdateDriverInputHandler
|
||||
@@ -64,15 +52,9 @@ import com.cobblemon.mod.common.client.net.storage.party.SetPartyPokemonHandler
|
||||
import com.cobblemon.mod.common.client.net.storage.party.SetPartyReferenceHandler
|
||||
import com.cobblemon.mod.common.client.net.storage.pc.*
|
||||
import com.cobblemon.mod.common.client.net.toast.ToastPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeAcceptanceChangedHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeCancelledHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeCompletedHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeOfferExpiredHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeOfferNotificationHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeProcessStartedHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeStartedHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeUpdatedHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.*
|
||||
import com.cobblemon.mod.common.net.PacketRegisterInfo
|
||||
import com.cobblemon.mod.common.net.messages.client.CalculateSeatPositionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.OpenBehaviourEditorPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.SetClientPlayerDataPacket
|
||||
@@ -85,29 +67,18 @@ import com.cobblemon.mod.common.net.messages.client.cooking.SeasoningRegistrySyn
|
||||
import com.cobblemon.mod.common.net.messages.client.cooking.ToggleCookingPotLidPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.*
|
||||
import com.cobblemon.mod.common.net.messages.client.debug.RequestOpenRidingStatsDebugGUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.debug.UpdateTrackedBrainDataPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.PokeSnackBlockParticlesPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SaccharineLogBlockParticlesPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.habitat.OpenHabitatBlockEditorPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.*
|
||||
import com.cobblemon.mod.common.net.messages.client.npc.CloseNPCEditorPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.npc.OpenNPCEditorPacket
|
||||
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.pasture.ClosePasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.OpenPasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonPasturedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonUnpasturedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.UpdatePastureConflictFlagPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.*
|
||||
import com.cobblemon.mod.common.net.messages.client.pokedex.ServerConfirmedRegisterPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.*
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.AddEvolutionPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.ClearEvolutionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.ClientboundSeatAssignmentPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.RemoveEvolutionPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.settings.OpenCobblemonConfigScreenPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
|
||||
@@ -123,52 +94,22 @@ import com.cobblemon.mod.common.net.messages.client.storage.party.InitializePart
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.party.MoveClientPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.party.SetPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.party.SetPartyReferencePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.ClosePCPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.InitializePCPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.MoveClientPCPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.OpenPCPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.RenamePCBoxPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCBoxPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.*
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.ChangePCBoxWallpaperPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.RequestPCBoxWallpapersPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.SetPCBoxWallpapersPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.UnlockPCBoxWallpaperPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.tms.TechnicalMachineRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.toast.ToastPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeAcceptanceChangedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeCancelledPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeCompletedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferExpiredPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferNotificationPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeProcessStartedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeUpdatedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.*
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.ExpGainedDataPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.PokedexUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.SetActiveTMPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.SetTMMachineContainerDataPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.SummaryUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.SynchronizeActiveTMPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.BattleChallengePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.BattleChallengeResponsePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.BenchMovePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.RequestMoveSwapPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.RequestPlayerInteractionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.SelectStarterPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.SendOutPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.BattleSelectActionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamLeavePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamRequestPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamResponsePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.RemoveSpectatorPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.SpectateBattlePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.*
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.*
|
||||
import com.cobblemon.mod.common.net.messages.server.behaviour.DamageOnCollisionPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.behaviour.SetEntityBehaviourPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.block.AdjustBlockEntityViewerCountPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.block.TMMachineTeachMovePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.breeding.TriggerEggHatchPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectCancelledPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectedPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.party.PartyPokemonSelectedPacket
|
||||
@@ -181,7 +122,6 @@ import com.cobblemon.mod.common.net.messages.server.debug.ServerboundUpdateRidin
|
||||
import com.cobblemon.mod.common.net.messages.server.debug.ServerboundUpdateRidingStatsPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.dialogue.EscapeDialoguePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.dialogue.InputToDialoguePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.habitat.SaveHabitatBlockSettingsPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.npc.SaveNPCPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.PasturePokemonPacket
|
||||
@@ -191,43 +131,25 @@ import com.cobblemon.mod.common.net.messages.server.pasture.UnpasturePokemonPack
|
||||
import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.FinishScanningPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.StartScanningPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.interact.InteractPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.ServerboundUpdateRidingStatePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetActiveMarkPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetItemHiddenPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetMarkingsPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetNicknamePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.*
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.evolution.AcceptEvolutionPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.DismountPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdatePassengerPositionPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateRiderRotationPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.starter.RequestStarterScreenPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.SwapPCPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.MovePartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.PartyTutorialPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.ReleasePartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.SwapPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.*
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.AcceptTradeRequestPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.CancelTradePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.ChangeTradeAcceptancePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.OfferTradePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.PerformTradePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.UpdateTradeOfferPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.*
|
||||
import com.cobblemon.mod.common.net.serverhandling.ChallengeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.ChallengeResponseHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.RequestInteractionsHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.BattleSelectActionsHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.RemoveSpectatorHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.SpectateBattleHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.TeamLeaveHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestResponseHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.*
|
||||
import com.cobblemon.mod.common.net.serverhandling.behaviour.DamageOnCollisionPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.behaviour.SetEntityBehaviourHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.block.AdjustBlockEntityViewerCountHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.block.TMMachineTeachMoveHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.breeding.TriggerEggHatchHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectCancelledHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectedHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.party.PartyPokemonSelectedHandler
|
||||
@@ -241,7 +163,6 @@ import com.cobblemon.mod.common.net.serverhandling.debug.ServerboundUpdateRiding
|
||||
import com.cobblemon.mod.common.net.serverhandling.dialogue.EscapeDialogueHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.dialogue.InputToDialogueHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.evolution.AcceptEvolutionHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.habitat.SaveHabitatBlockSettingsHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.npc.SaveNPCHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.orientation.ServerboundUpdateOrientationHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.PasturePokemonHandler
|
||||
@@ -251,14 +172,9 @@ import com.cobblemon.mod.common.net.serverhandling.pasture.UnpasturePokemonHandl
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokedex.scanner.FinishScanningHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokedex.scanner.StartScanningHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.interact.InteractPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.ServerboundUpdateRidingStateHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetActiveMarkHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetItemHiddenHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetMarkingsHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetNicknameHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.*
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.DismountPokemonPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.DriverInputPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.ServerboundUpdatePassengerPositionHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.ServerboundUpdateRiderRotationHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.starter.RequestStarterScreenHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.starter.SelectStarterPacketHandler
|
||||
@@ -267,16 +183,10 @@ import com.cobblemon.mod.common.net.serverhandling.storage.RequestMoveSwapHandle
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.SendOutPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.SwapPCPartyPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.party.MovePartyPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.party.PartyTutorialPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.party.ReleasePCPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.party.SwapPartyPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.pc.*
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.AcceptTradeRequestHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.CancelTradeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.ChangeTradeAcceptanceHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.OfferTradeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.PerformTradeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.UpdateTradeOfferHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.*
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
@@ -346,8 +256,6 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(MarkingsUpdatePacket.ID, MarkingsUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(RideBoostsUpdatePacket.ID, RideBoostsUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(RideStaminaUpdatePacket.ID, RideStaminaUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(AlphaUpdatePacket.ID, AlphaUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(ScaleModifierUpdatePacket.ID, ScaleModifierUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
|
||||
// Evolution start
|
||||
list.add(PacketRegisterInfo(AddEvolutionPacket.ID, AddEvolutionPacket::decode, PokemonUpdatePacketHandler()))
|
||||
@@ -381,7 +289,6 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(PlayerInteractOptionsPacket.ID, PlayerInteractOptionsPacket::decode, PlayerInteractOptionsHandler))
|
||||
list.add(PacketRegisterInfo(PokedexUIPacket.ID, PokedexUIPacket::decode, PokedexUIPacketHandler))
|
||||
list.add(PacketRegisterInfo(ExpGainedDataPacket.ID, ExpGainedDataPacket::decode, ExpGainedDataPacketHandler))
|
||||
list.add(PacketRegisterInfo(SynchronizeActiveTMPacket.ID, SynchronizeActiveTMPacket::decode, SynchronizeActiveTMHandler))
|
||||
|
||||
// Starter packets
|
||||
list.add(PacketRegisterInfo(OpenStarterUIPacket.ID, OpenStarterUIPacket::decode, StarterUIPacketHandler))
|
||||
@@ -425,7 +332,7 @@ object CobblemonNetwork {
|
||||
// Data registries
|
||||
list.add(PacketRegisterInfo(AbilityRegistrySyncPacket.ID, AbilityRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(CobblemonMechanicsSyncPacket.ID, CobblemonMechanicsSyncPacket::decode, CobblemonMechanicsSyncHandler))
|
||||
list.add(PacketRegisterInfo(PokemonInteractionsSyncPacket.ID, PokemonInteractionsSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(PokemonInteractionsSyncPacket.ID, PokemonInteractionsSyncPacket::decode, PokemonInteractionsSyncHandler))
|
||||
list.add(PacketRegisterInfo(MovesRegistrySyncPacket.ID, MovesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(BerryRegistrySyncPacket.ID, BerryRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(SpeciesRegistrySyncPacket.ID, SpeciesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
@@ -447,7 +354,6 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(BehaviourSyncPacket.ID, BehaviourSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkRegistrySyncPacket.ID, MarkRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(RideSettingsSyncPacket.ID, RideSettingsSyncPacket::decode, RideSettingsSyncHandler))
|
||||
list.add(PacketRegisterInfo(TechnicalMachineRegistrySyncPacket.ID, TechnicalMachineRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
|
||||
// Effects
|
||||
list.add(PacketRegisterInfo(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler))
|
||||
@@ -510,19 +416,15 @@ object CobblemonNetwork {
|
||||
// Pokédex scanning
|
||||
list.add(PacketRegisterInfo(ServerConfirmedRegisterPacket.ID, ServerConfirmedRegisterPacket::decode, ServerConfirmedRegisterHandler))
|
||||
|
||||
// Debug / cheats
|
||||
list.add(PacketRegisterInfo(CalculateSeatPositionsPacket.ID, CalculateSeatPositionsPacket::decode, CalculateSeatPositionsHandler))
|
||||
|
||||
// Riding
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateRidingStatePacket.ID, ClientboundUpdateRidingStatePacket::decode, ClientboundUpdateRidingStateHandler))
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateDriverInputPacket.ID, ClientboundUpdateDriverInputPacket::decode, ClientboundUpdateDriverInputHandler))
|
||||
list.add(PacketRegisterInfo(ClientboundSeatAssignmentPacket.ID, ClientboundSeatAssignmentPacket::decode, ClientboundSeatAssignmentPacketHandler))
|
||||
|
||||
// Habitat blocks
|
||||
list.add(PacketRegisterInfo(OpenHabitatBlockEditorPacket.ID, OpenHabitatBlockEditorPacket::decode, OpenHabitatBlockEditorHandler))
|
||||
|
||||
// Debug
|
||||
list.add(PacketRegisterInfo(OpenRidingStatsDebugGUIPacket.ID, OpenRidingStatsDebugGUIPacket::decode, OpenRidingStatsDebugGUIHandler))
|
||||
list.add(PacketRegisterInfo(UpdateTrackedBrainDataPacket.ID, UpdateTrackedBrainDataPacket::decode, UpdateTrackedBrainDataHandler))
|
||||
|
||||
|
||||
|
||||
return list
|
||||
}
|
||||
@@ -558,7 +460,7 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(ReleasePCPokemonPacket.ID, ReleasePCPokemonPacket::decode, ReleasePCPokemonHandler))
|
||||
list.add(PacketRegisterInfo(UnlinkPlayerFromPCPacket.ID, UnlinkPlayerFromPCPacket::decode, UnlinkPlayerFromPCHandler))
|
||||
|
||||
list.add(PacketRegisterInfo(RequestRenamePCBoxPacket.ID, RequestRenamePCBoxPacket::decode, RequestRenamePCBoxHandler))
|
||||
list.add(PacketRegisterInfo(RequestRenamePCBoxPacket.Companion.ID, RequestRenamePCBoxPacket.Companion::decode, RequestRenamePCBoxHandler))
|
||||
list.add(PacketRegisterInfo(PCBoxWallpapersPacket.ID, PCBoxWallpapersPacket::decode, PCBoxWallpapersHandler))
|
||||
list.add(PacketRegisterInfo(RequestChangePCBoxWallpaperPacket.ID, RequestChangePCBoxWallpaperPacket::decode, RequestChangePCBoxWallpaperHandler))
|
||||
list.add(PacketRegisterInfo(MarkPCBoxWallpapersSeenPacket.ID, MarkPCBoxWallpapersSeenPacket::decode, MarkPCBoxWallpapersSeenHandler))
|
||||
@@ -603,7 +505,6 @@ object CobblemonNetwork {
|
||||
|
||||
// Block entity
|
||||
list.add(PacketRegisterInfo(AdjustBlockEntityViewerCountPacket.ID, AdjustBlockEntityViewerCountPacket::decode, AdjustBlockEntityViewerCountHandler))
|
||||
list.add(PacketRegisterInfo(TMMachineTeachMovePacket.ID, TMMachineTeachMovePacket::decode, TMMachineTeachMoveHandler))
|
||||
|
||||
// Move select packets
|
||||
list.add(PacketRegisterInfo(MoveSelectedPacket.ID, MoveSelectedPacket::decode, MoveSelectedHandler))
|
||||
@@ -617,9 +518,6 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(PartyPokemonMoveSelectedPacket.ID, PartyPokemonMoveSelectedPacket::decode, PartyPokemonMoveSelectedHandler))
|
||||
list.add(PacketRegisterInfo(PartyMoveSelectCancelledPacket.ID, PartyMoveSelectCancelledPacket::decode, PartyMoveSelectCancelledHandler))
|
||||
|
||||
//Party move tutorial toasts packets
|
||||
list.add(PacketRegisterInfo(PartyTutorialPacket.ID, PartyTutorialPacket::decode, PartyTutorialPacketHandler))
|
||||
|
||||
// Dialogue packets
|
||||
list.add(PacketRegisterInfo(EscapeDialoguePacket.ID, EscapeDialoguePacket::decode, EscapeDialogueHandler))
|
||||
list.add(PacketRegisterInfo(InputToDialoguePacket.ID, InputToDialoguePacket::decode, InputToDialogueHandler))
|
||||
@@ -636,29 +534,17 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(DismountPokemonPacket.ID, DismountPokemonPacket::decode, DismountPokemonPacketHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateDriverInputPacket.ID, ServerboundUpdateDriverInputPacket::decode, DriverInputPacketHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRiderRotationPacket.ID, ServerboundUpdateRiderRotationPacket::decode, ServerboundUpdateRiderRotationHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdatePassengerPositionPacket.ID, ServerboundUpdatePassengerPositionPacket::decode, ServerboundUpdatePassengerPositionHandler))
|
||||
|
||||
// Cooking
|
||||
list.add(PacketRegisterInfo(ToggleCookingPotLidPacket.ID, ToggleCookingPotLidPacket::decode, ToggleCookingPotLidHandler))
|
||||
|
||||
// TM Machine
|
||||
list.add(PacketRegisterInfo(SetActiveTMPacket.ID, SetActiveTMPacket::decode, SetActiveTMPacketHandler))
|
||||
list.add(PacketRegisterInfo(SetTMMachineContainerDataPacket.ID, SetTMMachineContainerDataPacket::decode, SetTMMachineContainerDataPacketHandler))
|
||||
|
||||
// Breeding Packets
|
||||
list.add(PacketRegisterInfo(TriggerEggHatchPacket.ID, TriggerEggHatchPacket::decode, TriggerEggHatchHandler))
|
||||
|
||||
// Behaviour Packets
|
||||
list.add(PacketRegisterInfo(SetEntityBehaviourPacket.ID, SetEntityBehaviourPacket::decode, SetEntityBehaviourHandler))
|
||||
list.add(PacketRegisterInfo(DamageOnCollisionPacket.ID, DamageOnCollisionPacket::decode, DamageOnCollisionPacketHandler))
|
||||
|
||||
// Habitat blocks
|
||||
list.add(PacketRegisterInfo(SaveHabitatBlockSettingsPacket.ID, SaveHabitatBlockSettingsPacket::decode, SaveHabitatBlockSettingsHandler))
|
||||
|
||||
// Debug / cheats
|
||||
// Debug
|
||||
list.add(PacketRegisterInfo(RequestOpenRidingStatsDebugGUIPacket.ID, RequestOpenRidingStatsDebugGUIPacket::decode, RequestOpenRidingStatsDebugGUIHandler))
|
||||
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
|
||||
@@ -1,47 +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.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.npc.PartyComposition
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
|
||||
object CobblemonPartyCompositions : JsonDataRegistry<PartyComposition> {
|
||||
override val id: ResourceLocation = cobblemonResource("party_compositions")
|
||||
override val type = PackType.SERVER_DATA
|
||||
override val typeToken: TypeToken<PartyComposition> = TypeToken.get(PartyComposition::class.java)
|
||||
override val resourcePath: String = "party_compositions"
|
||||
override val observable = SimpleObservable<CobblemonPartyCompositions>()
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
|
||||
.setPrettyPrinting()
|
||||
.create()
|
||||
|
||||
val partyCompositions = mutableMapOf<ResourceLocation, PartyComposition>()
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
// probably worth syncing which exist, yeah. the deeper details probably not. I'll get to this eventually.
|
||||
}
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, PartyComposition>) {
|
||||
data.entries.forEach { it.value.id = it.key }
|
||||
partyCompositions.clear()
|
||||
partyCompositions.putAll(data)
|
||||
observable.emit(this)
|
||||
Cobblemon.LOGGER.info("Loaded ${data.size} party compositions.")
|
||||
}
|
||||
}
|
||||
@@ -1,60 +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.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.moves.MovesetBuilder
|
||||
import com.cobblemon.mod.common.api.npc.PartyPool
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.util.ScriptableIntRange
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IntRangeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.MovesetBuilderReferenceAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.PokemonPropertiesAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ScriptableIntRangeAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
|
||||
object CobblemonPartyPools : JsonDataRegistry<PartyPool> {
|
||||
override val id: ResourceLocation = cobblemonResource("party_pools")
|
||||
override val type = PackType.SERVER_DATA
|
||||
override val typeToken: TypeToken<PartyPool> = TypeToken.get(PartyPool::class.java)
|
||||
override val resourcePath: String = "party_pools"
|
||||
override val observable = SimpleObservable<CobblemonPartyPools>()
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
|
||||
.registerTypeAdapter(PokemonProperties::class.java, PokemonPropertiesAdapter(saveLong = false))
|
||||
.registerTypeAdapter(IntRange::class.java, IntRangeAdapter)
|
||||
.registerTypeAdapter(ScriptableIntRange::class.java, ScriptableIntRangeAdapter)
|
||||
.registerTypeAdapter(MovesetBuilder::class.java, MovesetBuilderReferenceAdapter)
|
||||
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
|
||||
.setPrettyPrinting()
|
||||
.create()
|
||||
|
||||
val partyPools = mutableMapOf<ResourceLocation, PartyPool>()
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
// probably worth syncing. Knowing the details might help exploit the server? lot of effort for little though.
|
||||
}
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, PartyPool>) {
|
||||
data.entries.forEach { it.value.id = it.key }
|
||||
partyPools.clear()
|
||||
partyPools.putAll(data)
|
||||
observable.emit(this)
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,6 @@ import net.minecraft.resources.ResourceKey
|
||||
import net.minecraft.world.entity.ai.village.poi.PoiType
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
|
||||
object CobblemonPoiTypes: PlatformRegistry<Registry<PoiType>, ResourceKey<Registry<PoiType>>, PoiType>() {
|
||||
override val registry: Registry<PoiType> = BuiltInRegistries.POINT_OF_INTEREST_TYPE
|
||||
@@ -31,12 +30,6 @@ object CobblemonPoiTypes: PlatformRegistry<Registry<PoiType>, ResourceKey<Regist
|
||||
// TODO after 1.7
|
||||
// @JvmField
|
||||
// val INCENSE_SWEET_KEY = createKey("incense_sweet", CobblemonBlocks.INCENSE_SWEET, 0, 1)
|
||||
@JvmField
|
||||
val HABITAT_BLOCK_KEY: ResourceKey<PoiType> = createKey("habitat_block", CobblemonBlocks.HABITAT_BLOCK, 0, 1)
|
||||
@JvmField
|
||||
val HABITAT_BLOCK = create(HABITAT_BLOCK_KEY.location().path, PoiType(getBlockStates(CobblemonBlocks.HABITAT_BLOCK), 0, 1))
|
||||
@JvmField
|
||||
val JUKEBOX_KEY = createKey("vanilla_jukebox", Blocks.JUKEBOX, 0, 1)
|
||||
|
||||
private fun createKey(string: String, block: Block, maxTickets: Int, validRange: Int ): ResourceKey<PoiType> =
|
||||
ResourceKey.create(Registries.POINT_OF_INTEREST_TYPE, cobblemonResource(string)).also { resourceKey ->
|
||||
|
||||
@@ -1,59 +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.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.api.types.adapters.ElementalTypeAdapter
|
||||
import com.cobblemon.mod.common.pokemon.ai.moves.RealTimeMove
|
||||
import com.cobblemon.mod.common.pokemon.ai.moves.events.MoveEventAction
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.RealTimeMoveConfigAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.RealTimeMoveEventActionConfigAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
|
||||
object CobblemonRealTimeMoves : JsonDataRegistry<RealTimeMove> {
|
||||
override val type = PackType.SERVER_DATA
|
||||
override val observable = SimpleObservable<CobblemonRealTimeMoves>()
|
||||
override val typeToken = TypeToken.get(RealTimeMove::class.java)
|
||||
override val resourcePath: String = "real_time_moves"
|
||||
override val id: ResourceLocation = cobblemonResource(resourcePath)
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
|
||||
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
|
||||
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
|
||||
.registerTypeAdapter(RealTimeMove::class.java, RealTimeMoveConfigAdapter)
|
||||
.registerTypeAdapter(MoveEventAction::class.java, RealTimeMoveEventActionConfigAdapter)
|
||||
.registerTypeAdapter(ElementalType::class.java, ElementalTypeAdapter)
|
||||
.create()
|
||||
|
||||
val realTimeMoves = mutableMapOf<ResourceLocation, RealTimeMove>()
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, RealTimeMove>) {
|
||||
realTimeMoves.clear()
|
||||
data.forEach { location, move -> move.id = location }
|
||||
realTimeMoves.putAll(data)
|
||||
}
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
// nah
|
||||
}
|
||||
}
|
||||
@@ -9,13 +9,13 @@
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.*
|
||||
import com.cobblemon.mod.common.pokemon.ai.PokemonDisturbancesSensor
|
||||
import com.cobblemon.mod.common.entity.sensor.BattlingPokemonSensor
|
||||
import com.cobblemon.mod.common.entity.sensor.NPCBattlingSensor
|
||||
import com.cobblemon.mod.common.pokemon.ai.PokemonDisturbancesSensor
|
||||
import java.util.function.Supplier
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.entity.ai.sensing.Sensor
|
||||
import net.minecraft.world.entity.ai.sensing.SensorType
|
||||
import java.util.function.Supplier
|
||||
|
||||
object CobblemonSensors {
|
||||
val sensors = mutableMapOf<String, SensorType<*>>()
|
||||
@@ -37,9 +37,6 @@ object CobblemonSensors {
|
||||
@JvmField
|
||||
val POKEMON_DEFEND_OWNER = register("pokemon_owner_under_attack", ::DefendOwnerSensor)
|
||||
|
||||
@JvmField
|
||||
val ALPHA_LEVEL_MATCHING = register("alpha_level_matching", ::AlphaLevelMatchingSensor)
|
||||
|
||||
@JvmField
|
||||
val NEARBY_GROWABLE_CROPS = register("nearby_growable_crops", ::PokemonGrowableCropSensor)
|
||||
|
||||
@@ -49,6 +46,9 @@ object CobblemonSensors {
|
||||
@JvmField
|
||||
val NEARBY_FLOWER = register("nearby_flower", ::FlowerSensor)
|
||||
|
||||
@JvmField
|
||||
val NEARBY_SWEET_BERRY_BUSH = register("nearby_sweet_berry_bush", ::SweetBerryBushSensor)
|
||||
|
||||
@JvmField
|
||||
val POKEMON_NEARBY_WANTED_ITEM = register("pokemon_nearby_wanted_item", ::PokemonItemSensor)
|
||||
|
||||
@@ -61,4 +61,4 @@ object CobblemonSensors {
|
||||
sensors[id] = sensor
|
||||
return sensor
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,9 +94,6 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
@JvmField
|
||||
val POKEDEX_SCAN_ZOOM_INCREMENT = this.create("item.pokedex.scan_zoom_increment")
|
||||
|
||||
@JvmField
|
||||
val BREEDING_EGG_HATCH = this.create("breeding.egg_hatch")
|
||||
|
||||
@JvmField
|
||||
val ITEM_USE = this.create("item.use")
|
||||
@JvmField
|
||||
@@ -111,9 +108,6 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
@JvmField
|
||||
val LEVELUP = this.create("gui.levelup")
|
||||
|
||||
@JvmField
|
||||
val MOVE_LEARN = this.create("gui.move_learn")
|
||||
|
||||
@JvmField
|
||||
val PVN_BATTLE = this.create("battle.pvn.default")
|
||||
@JvmField
|
||||
@@ -142,15 +136,6 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
@JvmField
|
||||
val MULCH_REMOVE = this.create("block.mulch.remove")
|
||||
|
||||
@JvmField
|
||||
val MONITOR_BREAK = this.create("block.monitor.break")
|
||||
@JvmField
|
||||
val MONITOR_INSERT = this.create("block.monitor.insert")
|
||||
@JvmField
|
||||
val MONITOR_LOADING = this.create("block.monitor.loading")
|
||||
@JvmField
|
||||
val MONITOR_GLITCHING = this.create("block.monitor.glitching")
|
||||
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_ACTIVATE = this.create("block.fossil_machine.activate")
|
||||
@JvmField
|
||||
@@ -215,28 +200,6 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
@JvmField
|
||||
val TUMBLESTONE_STEP = this.create("block.tumblestone.step")
|
||||
|
||||
@JvmField
|
||||
val TM_USE = this.create("item.tm.use")
|
||||
@JvmField
|
||||
val TM_MACHINE_BURN_LOOP = this.create("block.tm_machine.burn_loop")
|
||||
@JvmField
|
||||
val TM_MACHINE_CRAFT = this.create("block.tm_machine.craft")
|
||||
@JvmField
|
||||
val TM_MACHINE_START = this.create("block.tm_machine.start")
|
||||
@JvmField
|
||||
val TM_MACHINE_OPEN = this.create("block.tm_machine.open")
|
||||
@JvmField
|
||||
val TM_MACHINE_CLOSE = this.create("block.tm_machine.close")
|
||||
@JvmField
|
||||
val TM_MACHINE_TM_INSERT = this.create("block.tm_machine.tm_insert")
|
||||
@JvmField
|
||||
val TM_MACHINE_TM_RETRIEVE = this.create("block.tm_machine.tm_retrieve")
|
||||
@JvmField
|
||||
val TM_MACHINE_ITEM_INSERT = this.create("block.tm_machine.item_insert")
|
||||
@JvmField
|
||||
val TM_MACHINE_ITEM_RETRIEVE = this.create("block.tm_machine.item_retrieve")
|
||||
|
||||
|
||||
@JvmField
|
||||
val EVOLUTION_STONE_BLOCK_BREAK = this.create("block.evolution_stone_block.break")
|
||||
@JvmField
|
||||
@@ -275,9 +238,6 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
@JvmField
|
||||
val BERRY_EAT_FULL = this.create("item.berry.eat.full")
|
||||
|
||||
@JvmField
|
||||
val APRICORN_HARVEST = this.create("block.apricorn.harvest")
|
||||
|
||||
@JvmField
|
||||
val BIG_ROOT_BREAK = this.create("block.big_root.break")
|
||||
@JvmField
|
||||
@@ -352,13 +312,9 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val RIDE_LOOP_LEATHER_MONO = create("ride.loop.leather.mono")
|
||||
val RIDE_LOOP_LEATHER = create("ride.loop.leather")
|
||||
@JvmField
|
||||
val RIDE_LOOP_PLUMAGE_MONO = create("ride.loop.plumage.mono")
|
||||
@JvmField
|
||||
val RIDE_LOOP_LEATHER_STEREO = create("ride.loop.leather.stereo")
|
||||
@JvmField
|
||||
val RIDE_LOOP_PLUMAGE_STEREO = create("ride.loop.plumage.stereo")
|
||||
val RIDE_LOOP_PLUMAGE = create("ride.loop.plumage")
|
||||
|
||||
@JvmField
|
||||
val MOVE_QUICKATTACK_TARGET = this.create("move.quickattack.target")
|
||||
@@ -424,35 +380,6 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
TUMBLESTONE_STEP
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_BREAK = this.create("block.type_gem_block.break")
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_BREAK = this.create("block.type_gem_cluster.break")
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_HIT = this.create("block.type_gem_block.hit")
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_PLACE = this.create("block.type_gem_block.place")
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_STEP = this.create("block.type_gem_block.step")
|
||||
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_SOUNDS = SoundType(1f, 1.1f,
|
||||
TYPE_GEM_CLUSTER_BREAK,
|
||||
TYPE_GEM_BLOCK_STEP,
|
||||
TYPE_GEM_BLOCK_PLACE,
|
||||
TYPE_GEM_BLOCK_HIT,
|
||||
TYPE_GEM_BLOCK_STEP
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_SOUNDS = SoundType(1f, 1.1f,
|
||||
TYPE_GEM_BLOCK_BREAK,
|
||||
TYPE_GEM_BLOCK_STEP,
|
||||
TYPE_GEM_BLOCK_PLACE,
|
||||
TYPE_GEM_BLOCK_HIT,
|
||||
TYPE_GEM_BLOCK_STEP
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val EVOLUTION_STONE_BLOCK_SOUNDS = SoundType(1f, 1.1f,
|
||||
EVOLUTION_STONE_BLOCK_BREAK,
|
||||
@@ -634,31 +561,5 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
CAMPFIRE_POT_STEP
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val ITEM_BLOCK_PAPER_SMALL_PLACE = this.create("block.item_block.paper_small.place")
|
||||
@JvmField
|
||||
val ITEM_BLOCK_PAPER_SMALL_BREAK = this.create("block.item_block.paper_small.break")
|
||||
@JvmField
|
||||
val ITEM_BLOCK_PAPER_SMALL_SOUNDS = SoundType(1f, 1.1f,
|
||||
ITEM_BLOCK_PAPER_SMALL_BREAK,
|
||||
SoundEvents.WOOL_STEP,
|
||||
ITEM_BLOCK_PAPER_SMALL_PLACE,
|
||||
SoundEvents.WOOL_HIT,
|
||||
SoundEvents.WOOL_FALL
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val ITEM_BLOCK_PAPER_LARGE_PLACE = this.create("block.item_block.paper_large.place")
|
||||
@JvmField
|
||||
val ITEM_BLOCK_PAPER_LARGE_BREAK = this.create("block.item_block.paper_large.break")
|
||||
@JvmField
|
||||
val ITEM_BLOCK_PAPER_LARGE_SOUNDS = SoundType(1f, 1.1f,
|
||||
ITEM_BLOCK_PAPER_LARGE_BREAK,
|
||||
SoundEvents.WOOL_STEP,
|
||||
ITEM_BLOCK_PAPER_LARGE_PLACE,
|
||||
SoundEvents.WOOL_HIT,
|
||||
SoundEvents.WOOL_FALL
|
||||
)
|
||||
|
||||
private fun create(name: String): SoundEvent = this.create(name, SoundEvent.createVariableRangeEvent(cobblemonResource(name)))
|
||||
}
|
||||
|
||||
@@ -32,9 +32,6 @@ object CobblemonCriteria : PlatformRegistry<Registry<CriterionTrigger<*>>, Resou
|
||||
@JvmField
|
||||
val CATCH_SHINY_POKEMON = this.create("catch_shiny_pokemon", SimpleCriterionTrigger(CountableCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val CATCH_ALPHA_POKEMON = this.create("catch_alpha_pokemon", SimpleCriterionTrigger(CountableCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val EGG_COLLECT = this.create("eggs_collected", SimpleCriterionTrigger(CountableCriterion.CODEC))
|
||||
|
||||
@@ -81,20 +78,8 @@ object CobblemonCriteria : PlatformRegistry<Registry<CriterionTrigger<*>>, Resou
|
||||
@JvmField
|
||||
val PLANT_TUMBLESTONE = this.create("plant_tumblestone", SimpleCriterionTrigger(PlantTumblestoneCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val PLANT_TYPE_GEM = this.create("plant_type_gem", SimpleCriterionTrigger(PlantTypeGemCriterion.CODEC))
|
||||
|
||||
val RIDING_STAT_BOOST = this.create("riding_stat_boost", SimpleCriterionTrigger(RidingStatBoostCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val LEARN_TM = this.create("has_learn_specific_tm", SimpleCriterionTrigger(LearnTMCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val LEARN_ALL_TM = this.create("has_learn_all_tm", SimpleCriterionTrigger(LearnAllTMCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val LEARN_TM_COUNT = this.create("tms_learned", SimpleCriterionTrigger(CountableCriterion.CODEC))
|
||||
|
||||
override val registry = BuiltInRegistries.TRIGGER_TYPES
|
||||
override val resourceKey = Registries.TRIGGER_TYPE
|
||||
}
|
||||
-50
@@ -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.advancement.criterion
|
||||
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.advancements.critereon.ContextAwarePredicate
|
||||
import net.minecraft.advancements.critereon.EntityPredicate
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import java.util.Optional
|
||||
|
||||
class LearnTMContext(val tm: ResourceLocation)
|
||||
|
||||
class LearnTMCriterion(
|
||||
playerCtx: Optional<ContextAwarePredicate>,
|
||||
val tm: String
|
||||
) : SimpleCriterionCondition<LearnTMContext>(playerCtx) {
|
||||
companion object {
|
||||
val CODEC: Codec<LearnTMCriterion> = RecordCodecBuilder.create { it.group(
|
||||
EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter(LearnTMCriterion::playerCtx),
|
||||
Codec.STRING.optionalFieldOf("tm", "any").forGetter(LearnTMCriterion::tm)
|
||||
).apply(it, ::LearnTMCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayer, context: LearnTMContext): Boolean {
|
||||
return tm == "any" || context.tm == tm.asIdentifierDefaultingNamespace()
|
||||
}
|
||||
}
|
||||
|
||||
class LearnAllTMContext
|
||||
|
||||
class LearnAllTMCriterion(
|
||||
playerCtx: Optional<ContextAwarePredicate>
|
||||
) : SimpleCriterionCondition<LearnAllTMContext>(playerCtx) {
|
||||
companion object {
|
||||
val CODEC: Codec<LearnAllTMCriterion> = RecordCodecBuilder.create { it.group(
|
||||
EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter(LearnAllTMCriterion::playerCtx)
|
||||
).apply(it, ::LearnAllTMCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayer, context: LearnAllTMContext) = true
|
||||
}
|
||||
+39
-3
@@ -14,7 +14,7 @@ import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.advancements.critereon.ContextAwarePredicate
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import java.util.*
|
||||
import java.util.Optional
|
||||
|
||||
class PlantTumblestoneContext(val pos: BlockPos, val block: TumblestoneBlock)
|
||||
|
||||
@@ -29,6 +29,42 @@ class PlantTumblestoneCriterion(
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayer, context: PlantTumblestoneContext): Boolean {
|
||||
return context.block.canGrow(player.level().getBlockState(context.pos), context.pos, player.level())
|
||||
return context.block.canGrow(context.pos, player.level())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///**
|
||||
// * A criterion condition for when a tumblestone block is planted
|
||||
// * @param id The identifier of the criterion
|
||||
// * @param predicate The predicate for the criterion
|
||||
// *
|
||||
// * @author Aethen
|
||||
// * @since 02/28/2024
|
||||
// */
|
||||
//class PlantTumblestoneCriterionCondition(id: Identifier, predicate: LootContextPredicate) :
|
||||
// SimpleCriterionCondition<PlantTumblestoneContext>(id, predicate) {
|
||||
// override fun toJson(json: JsonObject) {
|
||||
// // Add properties to json if needed. None needed for this criterion
|
||||
// }
|
||||
//
|
||||
// override fun fromJson(json: JsonObject) {
|
||||
// // Parse properties from json if needed. None needed for this criterion
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Checks if the tumblestone block can grow at the given position
|
||||
// * @param player The player that planted the tumblestone block
|
||||
// * @param context The context of the criterion
|
||||
// * @return True if the tumblestone block can grow at the given position, false otherwise
|
||||
// */
|
||||
// override fun matches(player: ServerPlayer, context: PlantTumblestoneContext): Boolean {
|
||||
// return context.tumbleStoneBlock.canGrow(context.pos, player.level())
|
||||
// }
|
||||
//}
|
||||
//
|
||||
///**
|
||||
// * The context of the [PlantTumblestoneCriterionCondition]
|
||||
// * @param pos The position of the tumblestone block
|
||||
// * @param tumbleStoneBlock The tumblestone block
|
||||
// */
|
||||
//open class PlantTumblestoneContext(var pos: BlockPos, var tumbleStoneBlock: TumblestoneBlock)
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.advancement.criterion
|
||||
|
||||
import com.cobblemon.mod.common.block.TypeGemClusterBlock
|
||||
import com.cobblemon.mod.common.block.TypeGemCoreBlock
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.advancements.critereon.ContextAwarePredicate
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import java.util.*
|
||||
|
||||
class PlantTypeGemContext(val pos: BlockPos, val block: TypeGemClusterBlock)
|
||||
|
||||
class PlantTypeGemCriterion(
|
||||
playerCtx: Optional<ContextAwarePredicate>
|
||||
): SimpleCriterionCondition<PlantTypeGemContext>(playerCtx) {
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<PlantTypeGemCriterion> = RecordCodecBuilder.create { it.group(
|
||||
ContextAwarePredicate.CODEC.optionalFieldOf("player").forGetter(PlantTypeGemCriterion::playerCtx)
|
||||
).apply(it, ::PlantTypeGemCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayer, context: PlantTypeGemContext): Boolean {
|
||||
return player.level().getBlockState(context.pos).block is TypeGemCoreBlock
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -48,7 +48,7 @@ class RidingStatBoostCriterion(
|
||||
val max = context.pokemon.pokemon.getMaxRideBoost(rideStat).toDouble()
|
||||
val min = context.pokemon.pokemon.getBaseRideStat(rideStat).toDouble()
|
||||
val value = context.pokemon.getRideStat(rideStat, ridingStyle, min, max)
|
||||
val isSufficient = (value >= this.statValue && this.statValue > 0.0) || !context.pokemon.pokemon.canApplyRideBoost(rideStat)
|
||||
val isSufficient = (value >= this.statValue && this.statValue > 0.0) || !context.pokemon.pokemon.canAddRideBoost(rideStat)
|
||||
if (isSufficient && this.rideStat == "any") {
|
||||
return true
|
||||
} else if (!isSufficient && this.rideStat == "all") {
|
||||
|
||||
@@ -19,7 +19,6 @@ package com.cobblemon.mod.common.api
|
||||
open class PrioritizedList<T> : Iterable<T> {
|
||||
protected val priorityMap = mutableMapOf<Priority, MutableList<T>>()
|
||||
// Please don't change arraylist, we need insertion order
|
||||
// MutableList doesn't necessarily preserve insertion order apparently
|
||||
protected val ordered = arrayListOf<T>()
|
||||
|
||||
val mapping: Map<Priority, List<T>>
|
||||
@@ -27,8 +26,8 @@ open class PrioritizedList<T> : Iterable<T> {
|
||||
|
||||
private fun reorder() {
|
||||
ordered.clear()
|
||||
Priority.entries.forEach {
|
||||
priorityMap[it]?.let(ordered::addAll)
|
||||
Priority.values().forEach {
|
||||
priorityMap[it]?.let { ordered.addAll(it) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,51 +11,28 @@ package com.cobblemon.mod.common.api.abilities
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.api.PrioritizedList
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addAbilityPoolFunctions
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
|
||||
/**
|
||||
* A pool of potential abilities, as a [PrioritizedList]. The added logic of this subclass
|
||||
* is that it has selection logic. Given a species and a set of aspects, it will go through
|
||||
* each priority group, and if it can then it will pick from that group and return it. It also
|
||||
* returns the index of that ability within the type band it is.
|
||||
* each priority group, and if it can then it will pick from that group and return it.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since July 28th, 2022
|
||||
*/
|
||||
open class AbilityPool : PrioritizedList<PotentialAbility>() {
|
||||
val struct = ObjectValue(this)
|
||||
.also { it.addAbilityPoolFunctions(this) }
|
||||
|
||||
fun getInheritedAbility(parent: Pokemon): Ability? {
|
||||
if (parent.ability.forced) {
|
||||
return null
|
||||
}
|
||||
|
||||
val parentAbilityType = parent.form.abilities.find { it.template == parent.ability.template }?.type ?: return null // Should be impossible
|
||||
val matchingTypes = ordered.filter { it.type == parentAbilityType }
|
||||
val desiredIndex = parent.ability.index
|
||||
val matchingPotentialAbility = matchingTypes.getOrNull(desiredIndex) ?: return null
|
||||
return matchingPotentialAbility.template.create().also { it.index = desiredIndex }
|
||||
}
|
||||
|
||||
fun select(species: Species, aspects: Set<String>): Ability {
|
||||
val typeMap = ordered.groupBy { it.type }
|
||||
fun select(species: Species, aspects: Set<String>): Pair<Ability, Priority> {
|
||||
for (priority in Priority.entries) {
|
||||
val potentialAbilities = priorityMap[priority]?.filter { it.isSatisfiedBy(aspects) } ?: continue
|
||||
if (potentialAbilities.isNotEmpty()) {
|
||||
val selected = potentialAbilities.random()
|
||||
val ability = selected.template.create(priority = selected.priority)
|
||||
ability.index = typeMap[selected.type]!!.indexOf(selected)
|
||||
return ability
|
||||
return potentialAbilities.random().template.create() to priority
|
||||
}
|
||||
}
|
||||
|
||||
LOGGER.error("Unable to select an ability from the pool for $species and aspects: ${aspects.joinToString()}")
|
||||
LOGGER.error("Please show this to the Cobblemon developers!")
|
||||
Exception().printStackTrace()
|
||||
return Abilities.first().create()
|
||||
return Abilities.first().create() to Priority.LOWEST
|
||||
}
|
||||
}
|
||||
+3
-44
@@ -12,16 +12,13 @@ import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.BiggerBrain
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.objective.Objective
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.sense.Sense
|
||||
import com.cobblemon.mod.common.api.ai.config.BehaviourConfig
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
|
||||
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
|
||||
import com.cobblemon.mod.common.util.activityRegistry
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
@@ -49,15 +46,8 @@ class BehaviourConfigurationContext {
|
||||
val memories = mutableSetOf<MemoryModuleType<*>>()
|
||||
val sensors = mutableSetOf<SensorType<*>>()
|
||||
|
||||
val objectives = mutableMapOf<Int, MutableList<Objective>>()
|
||||
val senses = mutableSetOf<Sense>()
|
||||
|
||||
val onAdd = mutableListOf<ExpressionLike>()
|
||||
|
||||
init {
|
||||
memories.add(CobblemonMemories.NEST_DESPAWN_IMMUNE_UNTIL_TICK)
|
||||
}
|
||||
|
||||
fun getOrCreateActivity(activity: Activity): ActivityConfigurationContext {
|
||||
return activities.firstOrNull { it.activity == activity } ?: ActivityConfigurationContext(activity).also(activities::add)
|
||||
}
|
||||
@@ -78,22 +68,6 @@ class BehaviourConfigurationContext {
|
||||
this.sensors.addAll(sensors)
|
||||
}
|
||||
|
||||
fun addSenses(vararg senses: Sense) {
|
||||
addSenses(senses.toList())
|
||||
}
|
||||
|
||||
fun addSenses(senses: Collection<Sense>) {
|
||||
outer@for (sense in senses) {
|
||||
for (existingSense in this.senses) {
|
||||
if (existingSense.merge(sense)) {
|
||||
continue@outer
|
||||
}
|
||||
}
|
||||
this.senses.add(sense)
|
||||
this.addMemories(sense.memories)
|
||||
}
|
||||
}
|
||||
|
||||
fun addOnAddScript(script: ExpressionLike) {
|
||||
onAdd.add(script)
|
||||
}
|
||||
@@ -114,23 +88,8 @@ class BehaviourConfigurationContext {
|
||||
var brain = entity.brain
|
||||
// Apply the brain config
|
||||
if (entity is MoLangScriptingEntity) {
|
||||
val useBiggerBrain = objectives.isNotEmpty() || senses.isNotEmpty()
|
||||
brain = entity.assignNewBrainWithMemoriesAndSensors(dynamic, memories, if (useBiggerBrain) emptySet() else sensors)
|
||||
brain = entity.assignNewBrainWithMemoriesAndSensors(dynamic, memories, sensors)
|
||||
onAdd.forEach { runtime.resolve(it) }
|
||||
if (useBiggerBrain) {
|
||||
val wereDebugging = entity.biggerBrain.debuggingPlayers ?: emptySet()
|
||||
val biggerBrain = BiggerBrain(entity)
|
||||
entity.biggerBrain = biggerBrain
|
||||
addSenses(biggerBrain.senses)
|
||||
val orderedObjectives = objectives.entries.sortedBy { it.key }.flatMap { it.value }
|
||||
orderedObjectives.forEach(biggerBrain::registerObjective)
|
||||
biggerBrain.senses.addAll(senses)
|
||||
biggerBrain.debuggingPlayers.addAll(wereDebugging)
|
||||
return
|
||||
} else {
|
||||
val biggerBrain = BiggerBrain(entity)
|
||||
entity.biggerBrain = biggerBrain
|
||||
}
|
||||
}
|
||||
activities.forEach { it.apply(entity) }
|
||||
brain.setCoreActivities(coreActivities)
|
||||
@@ -177,4 +136,4 @@ class BehaviourConfigurationContext {
|
||||
}
|
||||
return struct
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,8 +42,7 @@ class CobblemonAttackTargetData(
|
||||
/** An expression that returns false when the target is no longer worth attacking. */
|
||||
var shouldContinue: Expression = "true".asExpression(),
|
||||
var hitsUntilDisengage: Int = -1, // -1 means no limit
|
||||
var disengageAction: (entity: Entity) -> Unit = {},
|
||||
var hitsLanded : Int = 0
|
||||
var disengageAction: (entity: Entity) -> Unit = {}
|
||||
) {
|
||||
val struct = ObjectValue<CobblemonAttackTargetData>(this).also {
|
||||
it.addFunction("hits_until_disengage") { DoubleValue(hitsUntilDisengage.toDouble()) }
|
||||
|
||||
@@ -9,40 +9,44 @@
|
||||
package com.cobblemon.mod.common.api.ai
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.util.getBooleanOrNull
|
||||
import com.cobblemon.mod.common.util.getDoubleOrNull
|
||||
import kotlin.math.sqrt
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
|
||||
/**
|
||||
* Used to maintain some settings around how the entity should wander this tick. Anything left null
|
||||
* will fall back to defaults specified by the logic of the WanderAround objective.
|
||||
* Used to maintain some settings around how the entity should wander this tick. The idea is you
|
||||
* reset this with some script task at priority 0 then some number of steps before it gets to the wander
|
||||
* tasks you can have other conditional tasks jump in to configure parts of this.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since July 18, 2025
|
||||
*/
|
||||
class CobblemonWanderControl(
|
||||
var center: WanderCenter? = null,
|
||||
var maxAttempts: Int? = null, // How many times to try to find a suitable point before giving up on that tick.
|
||||
var allowLand: Boolean? = null,
|
||||
var allowWater: Boolean? = null,
|
||||
var allowAir: Boolean? = null,
|
||||
var wanderSpeed: Float? = null,
|
||||
var wanderChanceMultiplier: Float? = null
|
||||
var maxAttempts: Int = 4, // How many times to try to find a suitable point before giving up on that tick.
|
||||
var allowLand: Boolean = true,
|
||||
var allowWater: Boolean = false,
|
||||
var allowAir: Boolean = false,
|
||||
var pathCooldownTicks: Int = 20 * 5, // Used to mitigate the cost of pathfinding.
|
||||
var wanderSpeed: Float = 0.35F,
|
||||
) {
|
||||
class WanderCenter(val x: Number, val y: Number, val z: Number, val minRange: Float, val maxRange: Float)
|
||||
|
||||
@Transient
|
||||
val struct: QueryStruct = QueryStruct(hashMapOf())
|
||||
.addFunction("center_x") { DoubleValue(center?.x ?: 0.0) }
|
||||
.addFunction("center_y") { DoubleValue(center?.y ?: 0.0) }
|
||||
.addFunction("center_z") { DoubleValue(center?.z ?: 0.0) }
|
||||
.addFunction("max_attempts") { DoubleValue(maxAttempts?.toDouble() ?: 0.0) }
|
||||
.addFunction("min_range") { DoubleValue(center?.minRange ?: 0.0) }
|
||||
.addFunction("max_range") { DoubleValue(center?.maxRange ?: 0.0) }
|
||||
.addFunction("allow_land") { DoubleValue(if (allowLand == true) 1.0 else 0.0) }
|
||||
.addFunction("allow_water") { DoubleValue(if (allowWater == true) 1.0 else 0.0) }
|
||||
.addFunction("allow_air") { DoubleValue(if (allowAir == true) 1.0 else 0.0) }
|
||||
.addFunction("wander_speed") { DoubleValue(wanderSpeed ?: 0.0) }
|
||||
.addFunction("center_x") { center?.x ?: 0.0 }
|
||||
.addFunction("center_y") { center?.y ?: 0.0 }
|
||||
.addFunction("center_z") { center?.z ?: 0.0 }
|
||||
.addFunction("max_attempts") { maxAttempts.toDouble() }
|
||||
.addFunction("min_range") { center?.minRange ?: 0.0 }
|
||||
.addFunction("max_range") { center?.maxRange ?: 0.0 }
|
||||
.addFunction("allow_land") { if (allowLand) 1.0 else 0.0 }
|
||||
.addFunction("allow_water") { if (allowWater) 1.0 else 0.0 }
|
||||
.addFunction("allow_air") { if (allowAir) 1.0 else 0.0 }
|
||||
.addFunction("path_cooldown_ticks") { pathCooldownTicks.toDouble() }
|
||||
.addFunction("wander_speed") { wanderSpeed }
|
||||
.addFunction("set_center") { params ->
|
||||
if (params.params.size < 3) {
|
||||
throw IllegalArgumentException("set_center requires at least 3 parameters: x, y, z")
|
||||
@@ -64,6 +68,26 @@ class CobblemonWanderControl(
|
||||
.addFunction("set_allow_land") { params -> allowLand = params.getBooleanOrNull(0) ?: true }
|
||||
.addFunction("set_allow_water") { params -> allowWater = params.getBooleanOrNull(0) ?: false }
|
||||
.addFunction("set_allow_air") { params -> allowAir = params.getBooleanOrNull(0) ?: false }
|
||||
.addFunction("set_path_cooldown_ticks") { params -> pathCooldownTicks = params.getDoubleOrNull(0)?.toInt() ?: (20 * 5) }
|
||||
.addFunction("set_wander_speed") { params -> wanderSpeed = params.getDoubleOrNull(0)?.toFloat() ?: 0.35F }
|
||||
.addFunction("reset") { reset() }
|
||||
|
||||
fun isSuitable(position: BlockPos): Boolean {
|
||||
val center = center ?: return true
|
||||
val centerPos = BlockPos(center.x.toInt(), center.y.toInt(), center.z.toInt())
|
||||
val distance = sqrt(centerPos.distSqr(position))
|
||||
val suitable = distance >= center.minRange && distance <= center.maxRange
|
||||
return suitable
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
center = null
|
||||
allowLand = false
|
||||
allowWater = false
|
||||
allowAir = false
|
||||
pathCooldownTicks = 20 * 5
|
||||
wanderSpeed = 0.35F
|
||||
maxAttempts = 4
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,23 +9,9 @@
|
||||
package com.cobblemon.mod.common.api.ai
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.ast.NumberExpression
|
||||
import com.bedrockk.molang.ast.StringExpression
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveDouble
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
import com.cobblemon.mod.common.util.resolveString
|
||||
import com.mojang.datafixers.util.Either
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
/**
|
||||
* The issue in a lot of the behaviour datapacking is that there are times when a property should be exposed to
|
||||
@@ -45,50 +31,6 @@ import net.minecraft.world.entity.LivingEntity
|
||||
*/
|
||||
typealias ExpressionOrEntityVariable = Either<Expression, MoLangConfigVariable>
|
||||
|
||||
fun ExpressionOrEntityVariable.asExpression() = map({ it }, { "q.entity.config.${it.variableName}".asExpression() })
|
||||
fun ExpressionOrEntityVariable.resolveString(runtime: MoLangRuntime) = runtime.resolveString(asExpression())
|
||||
fun ExpressionOrEntityVariable.resolveBoolean(runtime: MoLangRuntime) = runtime.resolveBoolean(asExpression())
|
||||
fun ExpressionOrEntityVariable.resolveInt(runtime: MoLangRuntime) = runtime.resolveInt(asExpression())
|
||||
fun ExpressionOrEntityVariable.resolveDouble(runtime: MoLangRuntime) = runtime.resolveDouble(asExpression())
|
||||
fun ExpressionOrEntityVariable.resolveFloat(runtime: MoLangRuntime) = runtime.resolveFloat(asExpression())
|
||||
|
||||
private fun variable(category: String, name: String, type: MoLangConfigVariable.MoLangVariableType, default: String) = MoLangConfigVariable(
|
||||
variableName = name,
|
||||
category = lang("entity.variable.category.$category"),
|
||||
displayName = lang("entity.variable.$name.name"),
|
||||
description = lang("entity.variable.$name.desc"),
|
||||
type = type,
|
||||
defaultValue = default
|
||||
)
|
||||
|
||||
fun stringVariable(category: String, name: String, default: String) = variable(category = category, name = name, type = MoLangConfigVariable.MoLangVariableType.TEXT, default = default)
|
||||
fun numberVariable(category: String, name: String, default: Number) = variable(category = category, name = name, type = MoLangConfigVariable.MoLangVariableType.NUMBER, default = default.toString())
|
||||
fun booleanVariable(category: String, name: String, default: Boolean) = variable(category = category, name = name, type = MoLangConfigVariable.MoLangVariableType.BOOLEAN, default = default.toString())
|
||||
|
||||
fun getVariableExpression(name: String) = "q.entity.config.$name".asExpression()
|
||||
fun resolveBooleanVariable(name: String, runtime: MoLangRuntime) = runtime.resolveBoolean(getVariableExpression(name))
|
||||
|
||||
fun checkCondition(runtime: MoLangRuntime, expressionOrEntityVariable: ExpressionOrEntityVariable): Boolean {
|
||||
return expressionOrEntityVariable.resolveBoolean(runtime)
|
||||
}
|
||||
|
||||
fun ExpressionOrEntityVariable.asSimplifiedExpression(entity: LivingEntity): Expression {
|
||||
return map(
|
||||
{ it },
|
||||
{
|
||||
if (entity is MoLangScriptingEntity) {
|
||||
val variable = entity.config.map[it.variableName]
|
||||
if (variable is DoubleValue) {
|
||||
return@map NumberExpression(variable.value)
|
||||
} else if (variable is StringValue) {
|
||||
return@map StringExpression(variable)
|
||||
}
|
||||
}
|
||||
return@map "q.entity.config.${it.variableName}".asExpression()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* In the case of [ExpressionOrEntityVariable] the right side is the only one that requires visibility for a user,
|
||||
* this function is a shorthand for finding all of the values in the list that have something to show the user to
|
||||
|
||||
@@ -1,193 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.PrioritizedList
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.Distraction
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.EntityFixation
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.objective.Objective
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.objective.ObjectiveStatus
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.sense.Sense
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.net.messages.client.debug.UpdateTrackedBrainDataPacket
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import com.cobblemon.mod.common.util.getPlayer
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
* A better* version of Minecraft's [net.minecraft.world.entity.ai.Brain] system that makes development more
|
||||
* straightforward and allows easier debugging.
|
||||
*
|
||||
* We could name this thing better.
|
||||
*
|
||||
* There are three main principles inside this system:
|
||||
*
|
||||
* 1: Senses
|
||||
*
|
||||
* Senses are simple ticking objects that are instantiated per entity and are expected to just update memories based
|
||||
* on properties about the entity or its surroundings. This is an analogue of SensorType from Brains.
|
||||
*
|
||||
* 2: Objectives
|
||||
*
|
||||
* Objectives are also ticking objects that are instantiated per entity. They represent a goal for the entity and
|
||||
* run in a fixed order.
|
||||
*
|
||||
* 3: Fixations
|
||||
*
|
||||
* Fixations are a task that can be set on the brain that represents a more total commitment to a certain task. Only
|
||||
* a single fixation can be active at a time, and they can be 'distracted' by other objectives or potentially external
|
||||
* factors.
|
||||
*
|
||||
* These can also be debugged using the /debugcobblemonai command while looking at a Pokémon or NPC entity.
|
||||
*
|
||||
* *that remains to be seen
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 29th, 2025
|
||||
*/
|
||||
class BiggerBrain(val entity: LivingEntity) {
|
||||
val runtime = MoLangRuntime().setup().withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
|
||||
val senses = mutableListOf<Sense>()
|
||||
val objectives = mutableListOf<Objective>()
|
||||
val subscriptions = mutableMapOf<MemoryModuleType<*>, PrioritizedList<MemorySubscription<*>>>()
|
||||
|
||||
class MemorySubscription<U>(
|
||||
val subscription: (U?, labels: MutableSet<String>) -> Boolean
|
||||
) {
|
||||
fun handle(value: Any?, labels: MutableSet<String>): Boolean {
|
||||
val castValue = value as? U
|
||||
return subscription(castValue, labels)
|
||||
}
|
||||
}
|
||||
|
||||
fun <U, M : MemoryModuleType<U>> subscribe(priority: Priority = Priority.NORMAL, memory: M, handler: (U?, labels: MutableSet<String>) -> Boolean) {
|
||||
subscriptions
|
||||
.getOrPut(memory, ::PrioritizedList)
|
||||
.add(priority, MemorySubscription(handler))
|
||||
}
|
||||
|
||||
var fixation: EntityFixation? = null
|
||||
|
||||
var debuggingPlayers = mutableSetOf<UUID>()
|
||||
|
||||
fun registerObjective(objective: Objective) {
|
||||
objectives.add(objective)
|
||||
objective.onRegister(entity, this)
|
||||
}
|
||||
|
||||
fun isFixation(fixation: EntityFixation?): Boolean {
|
||||
return fixation != null && this.fixation == fixation
|
||||
}
|
||||
|
||||
fun sendDebugMessage(message: String) {
|
||||
debuggingPlayers.forEach {
|
||||
it.getPlayer()?.sendSystemMessage(message.text())
|
||||
}
|
||||
}
|
||||
|
||||
fun tick() {
|
||||
senses.forEach {
|
||||
it.ticksUntilNextExecution--
|
||||
if (it.ticksUntilNextExecution <= 0) {
|
||||
it.tick(entity, this)
|
||||
}
|
||||
}
|
||||
|
||||
if (fixation?.tick(entity, this) == false) {
|
||||
fixation = null
|
||||
}
|
||||
|
||||
val objectiveStatuses = mutableMapOf<Objective, ObjectiveStatus>()
|
||||
|
||||
val activeObjectiveTags = mutableSetOf<String>()
|
||||
for (objective in objectives) {
|
||||
val status = objective.perform(entity, this, activeObjectiveTags)
|
||||
objectiveStatuses[objective] = status
|
||||
}
|
||||
|
||||
if (debuggingPlayers.isNotEmpty()) {
|
||||
val state = BiggerBrainState(entity = entity, brain = this, objectiveStatuses = objectiveStatuses)
|
||||
val packet = UpdateTrackedBrainDataPacket(entity.id, state)
|
||||
debuggingPlayers.removeIf { uuid ->
|
||||
val player = uuid.getPlayer()
|
||||
if (player != null && Cobblemon.serverPlayerDebuggingPokemonBrainEntities[player.uuid] != entity.uuid) {
|
||||
return@removeIf true
|
||||
} else {
|
||||
player?.sendPacket(packet)
|
||||
}
|
||||
return@removeIf player == null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun fixate(fixation: EntityFixation): EntityFixation {
|
||||
this.fixation = fixation
|
||||
return fixation
|
||||
}
|
||||
|
||||
fun distract(distraction: Distraction): Boolean {
|
||||
if (fixation?.canDistract(distraction, entity) != false) {
|
||||
fixation?.onDistract(distraction, entity)
|
||||
this.fixation = null
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun canDistract(distraction: Distraction): Boolean {
|
||||
return fixation?.canDistract(distraction, entity) != false
|
||||
}
|
||||
|
||||
fun <T> setMemory(memory: MemoryModuleType<T>, value: T, expiry: Long? = null) {
|
||||
if (expiry != null) {
|
||||
entity.brain.setMemoryWithExpiry(memory, value, expiry)
|
||||
} else {
|
||||
entity.brain.setMemory(memory, value)
|
||||
}
|
||||
val labels = mutableSetOf<String>()
|
||||
subscriptions[memory]?.forEach { it.handle(value = value, labels = labels) }
|
||||
}
|
||||
|
||||
fun <T> setMemoryIfChanged(memory: MemoryModuleType<T>, value: T, expiry: Long? = null) {
|
||||
if (entity.brain.getMemorySafely(memory).orElse(null) != value) {
|
||||
setMemory(memory, value, expiry)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> eraseMemory(memory: MemoryModuleType<T>) {
|
||||
entity.brain.eraseMemory(memory)
|
||||
val labels = mutableSetOf<String>()
|
||||
subscriptions[memory]?.forEach { it.handle(value = null, labels = labels) }
|
||||
}
|
||||
|
||||
fun <T> eraseMemoryIfPresent(memory: MemoryModuleType<T>) {
|
||||
if (entity.brain.hasMemoryValue(memory)) {
|
||||
eraseMemory(memory)
|
||||
}
|
||||
}
|
||||
|
||||
fun hasMemoryValue(memory: MemoryModuleType<*>): Boolean {
|
||||
return entity.brain.checkMemory(memory, MemoryStatus.VALUE_PRESENT)
|
||||
}
|
||||
|
||||
fun <T> getMemory(memory: MemoryModuleType<T>): T? {
|
||||
return entity.brain.getMemorySafely(memory).orElse(null)
|
||||
}
|
||||
}
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.objective.Objective
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.objective.ObjectiveStatus
|
||||
import kotlin.reflect.jvm.jvmName
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
/**
|
||||
* A DTO of sorts that is sent to debugging players to keep them informed about the state of an entity's Cobblemon AI.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 29th, 2025
|
||||
*/
|
||||
class BiggerBrainState(
|
||||
val senses: List<SenseState>,
|
||||
val objectives: List<ObjectiveState>,
|
||||
val fixation: String? = null
|
||||
) {
|
||||
class SenseState(val className: String, val ticksUntilNextExecution: Int) {
|
||||
fun encode(buffer: FriendlyByteBuf) {
|
||||
buffer.writeUtf(className)
|
||||
buffer.writeInt(ticksUntilNextExecution)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun decode(buffer: FriendlyByteBuf): SenseState {
|
||||
return SenseState(buffer.readUtf(), buffer.readInt())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ObjectiveState(val description: String, val status: ObjectiveStatus) {
|
||||
fun encode(buffer: FriendlyByteBuf) {
|
||||
buffer.writeUtf(description)
|
||||
buffer.writeEnum(status)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun decode(buffer: FriendlyByteBuf): ObjectiveState {
|
||||
return ObjectiveState(buffer.readUtf(), buffer.readEnum(ObjectiveStatus::class.java))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor(entity: LivingEntity, brain: BiggerBrain, objectiveStatuses: Map<Objective, ObjectiveStatus>): this(
|
||||
senses = brain.senses.map { SenseState(className = it::class.simpleName ?: it::class.jvmName, it.ticksUntilNextExecution) },
|
||||
objectives = objectiveStatuses.entries.map { ObjectiveState(it.key.getDescription(entity), it.value) },
|
||||
fixation = brain.fixation?.getDescription(entity)
|
||||
)
|
||||
|
||||
fun encode(buffer: FriendlyByteBuf) {
|
||||
buffer.writeCollection(senses) { _, sense -> sense.encode(buffer) }
|
||||
buffer.writeCollection(objectives) { _, objective -> objective.encode(buffer) }
|
||||
buffer.writeNullable(fixation) { _, fixation -> buffer.writeUtf(fixation) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun decode(buffer: FriendlyByteBuf): BiggerBrainState {
|
||||
val senses = buffer.readList { SenseState.decode(it) }
|
||||
val objectives = buffer.readList { ObjectiveState.decode(it) }
|
||||
val fixation = buffer.readNullable { buffer.readUtf() }
|
||||
return BiggerBrainState(senses, objectives, fixation)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain
|
||||
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.behavior.EntityTracker
|
||||
import net.minecraft.world.entity.ai.behavior.PositionTracker
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
|
||||
/**
|
||||
* A trivial wrapper around an entity and a position tracker to make the entity look at the position each tick.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 29th, 2025
|
||||
*/
|
||||
class LookingTracker(val entity: PathfinderMob, val lookTarget: PositionTracker) {
|
||||
companion object {
|
||||
fun forTargetEntity(entity: PathfinderMob, target: LivingEntity, trackEyeHeight: Boolean = true): LookingTracker {
|
||||
return LookingTracker(entity, EntityTracker(target, trackEyeHeight))
|
||||
}
|
||||
|
||||
fun fromNavigationPathOrWalkTarget(entity: PathfinderMob, walkTarget: WalkTarget): LookingTracker {
|
||||
val destinationPoint = entity.navigation.path?.endNode?.asVec3() ?: walkTarget.target.currentPosition()
|
||||
return LookingTracker(entity, BlockPosTracker(destinationPoint.add(0.0, entity.eyeHeight.toDouble(), 0.0)))
|
||||
}
|
||||
}
|
||||
fun tick() {
|
||||
entity.lookControl.setLookAt(lookTarget.currentPosition())
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain
|
||||
|
||||
/**
|
||||
* A simple enum representing the status of a movement action.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 29th, 2025
|
||||
*/
|
||||
enum class MovementStatus {
|
||||
/** Represents when the entity is still en route to the destination. */
|
||||
PENDING,
|
||||
/** Represents when the entity has successfully reached the destination. */
|
||||
COMPLETED,
|
||||
/**
|
||||
* Represents when the entity has failed to reach the destination. This can be due to
|
||||
* a change in surroundings or taking too long or all sorts of things.
|
||||
*/
|
||||
FAILED
|
||||
}
|
||||
@@ -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.api.ai.biggerbrain
|
||||
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
|
||||
/**
|
||||
* A wrapping around logic that maintains an entity's journey towards a specific destination. Mainly used by fixations
|
||||
* to keep track of when pathing is done, and whether it failed or succeeded. Can also be told to stop to do any
|
||||
* necessary clean up. Implemented only by [RegularMovementTracker] which has me questioning if it should be an interface
|
||||
* or just a simple class like the [LookingTracker].
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 29th, 2025
|
||||
*/
|
||||
interface MovementTracker {
|
||||
val walkTarget: WalkTarget
|
||||
/** The last known status of this movement tracker. */
|
||||
var lastStatus: MovementStatus
|
||||
/** Performs a tick of movement tracking logic. Returns the current [MovementStatus]. */
|
||||
fun tick(): MovementStatus
|
||||
/** Stops the movement and does any necessary clean up. */
|
||||
fun stop()
|
||||
}
|
||||
-209
@@ -1,209 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain
|
||||
|
||||
import com.cobblemon.mod.common.entity.ai.CobblemonWalkTarget
|
||||
import com.cobblemon.mod.common.pokemon.ai.OmniPathNodeMaker
|
||||
import com.cobblemon.mod.common.util.deleteNode
|
||||
import java.util.function.Predicate
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.EntityTracker
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.entity.ai.util.DefaultRandomPos
|
||||
import net.minecraft.world.level.pathfinder.Path
|
||||
import net.minecraft.world.level.pathfinder.PathType
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
/**
|
||||
* The default movement tracker used for tracking movement towards a [WalkTarget]. This is pretty much entirely
|
||||
* just the code for FollowWalkTargetTask from Minecraft brain stuff.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 29th, 2025
|
||||
*/
|
||||
class RegularMovementTracker(
|
||||
val entity: PathfinderMob,
|
||||
override val walkTarget: WalkTarget
|
||||
) : MovementTracker {
|
||||
companion object {
|
||||
/**
|
||||
* Attempts to create a tracker for the given entity and target. Returns null if the path
|
||||
* couldn't be created.
|
||||
*/
|
||||
fun attempt(entity: PathfinderMob, walkTarget: WalkTarget): RegularMovementTracker? {
|
||||
return RegularMovementTracker(entity, walkTarget).takeIf { it.isValid }
|
||||
}
|
||||
}
|
||||
|
||||
var isValid = false
|
||||
private set
|
||||
var started = false
|
||||
|
||||
override var lastStatus: MovementStatus = MovementStatus.PENDING
|
||||
private var path: Path? = null
|
||||
private var lastKnownTargetPos: BlockPos? = null
|
||||
|
||||
init {
|
||||
val hasReached = hasReached(entity, walkTarget)
|
||||
if (!hasReached && hasFinishedPath(entity, walkTarget)) {
|
||||
this.lastKnownTargetPos = walkTarget.target.currentBlockPosition()
|
||||
isValid = true
|
||||
} else {
|
||||
lastStatus = MovementStatus.FAILED
|
||||
}
|
||||
}
|
||||
|
||||
override fun tick(): MovementStatus {
|
||||
val path = path
|
||||
val status = if (path == null || isTargetSpectator(walkTarget)) {
|
||||
stop(entity)
|
||||
MovementStatus.FAILED
|
||||
} else if (hasReached(entity, walkTarget)) {
|
||||
stop(entity)
|
||||
MovementStatus.COMPLETED
|
||||
} else if (started && entity.navigation.isDone) {
|
||||
stop(entity)
|
||||
MovementStatus.FAILED
|
||||
} else {
|
||||
if (!started) {
|
||||
startOnPath(entity)
|
||||
started = true
|
||||
}
|
||||
|
||||
tick(entity)
|
||||
MovementStatus.PENDING
|
||||
}
|
||||
this.lastStatus = status
|
||||
return status
|
||||
}
|
||||
|
||||
fun startOnPath(entity: PathfinderMob) {
|
||||
entity.brain.setMemory(MemoryModuleType.PATH, this.path)
|
||||
entity.navigation.moveTo(this.path, walkTarget.speedModifier.toDouble())
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
stop(entity)
|
||||
}
|
||||
|
||||
fun stop(entity: PathfinderMob) {
|
||||
entity.navigation.stop()
|
||||
entity.brain.eraseMemory(MemoryModuleType.WALK_TARGET)
|
||||
entity.brain.eraseMemory(MemoryModuleType.PATH)
|
||||
}
|
||||
|
||||
private fun tick(entity: PathfinderMob) {
|
||||
val path = entity.navigation.path
|
||||
if (this.path !== path) {
|
||||
this.path = path
|
||||
this.startOnPath(entity)
|
||||
}
|
||||
|
||||
if (path != null && lastKnownTargetPos != null) {
|
||||
if (walkTarget.target.currentBlockPosition().distSqr(lastKnownTargetPos!!) > 4.0) {
|
||||
// The target has moved away from where we are pathing, try pathing to its new location
|
||||
if (hasFinishedPath(entity, walkTarget)) {
|
||||
lastKnownTargetPos = walkTarget.target.currentBlockPosition()
|
||||
startOnPath(entity)
|
||||
} else {
|
||||
// Uh oh, we can't get closer? Maybe next tick will be better?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun withNodeFilter(
|
||||
entity: PathfinderMob,
|
||||
nodeFilter: Predicate<PathType>,
|
||||
block: () -> Unit) {
|
||||
val nodeEvaluator = entity.navigation.nodeEvaluator
|
||||
if (nodeEvaluator is OmniPathNodeMaker) {
|
||||
nodeEvaluator.nodeFilter = nodeFilter
|
||||
block()
|
||||
nodeEvaluator.nodeFilter = Predicate { true }
|
||||
} else {
|
||||
block()
|
||||
}
|
||||
}
|
||||
|
||||
private fun hasFinishedPath(entity: PathfinderMob, walkTarget: WalkTarget): Boolean {
|
||||
val blockPos = walkTarget.target.currentBlockPosition()
|
||||
this.path = generatePath(entity, walkTarget, blockPos)
|
||||
val hasReached = hasReached(entity, walkTarget)
|
||||
if (!hasReached && path == null) {
|
||||
// Desperate attempt to still path to the destination by going somewhere in the vicinity
|
||||
val vec3d = DefaultRandomPos.getPosTowards(
|
||||
entity,
|
||||
10,
|
||||
7,
|
||||
Vec3.atBottomCenterOf(blockPos),
|
||||
Math.PI / 2F
|
||||
)
|
||||
if (vec3d != null) {
|
||||
this.path = generatePath(entity, walkTarget, BlockPos.containing(vec3d))
|
||||
return this.path != null
|
||||
}
|
||||
} else if (!hasReached) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun generatePath(
|
||||
entity: PathfinderMob,
|
||||
walkTarget: WalkTarget,
|
||||
target: BlockPos
|
||||
): Path? {
|
||||
var path: Path? = null
|
||||
if (walkTarget is CobblemonWalkTarget) {
|
||||
withNodeFilter(
|
||||
entity = entity,
|
||||
nodeFilter = walkTarget.nodeTypeFilter,
|
||||
) {
|
||||
var resolvedPath = entity.navigation.createPath(
|
||||
walkTarget.target.currentBlockPosition(),
|
||||
0
|
||||
)
|
||||
if (resolvedPath != null) {
|
||||
// A CobblemonWalkTarget may have a destinationNodeTypeFilter, which is used to filter the end node of the path.
|
||||
// Mainly useful for when the thing setting the target did it a bit crudely or didn't know how far the navigator
|
||||
// was going to get, and might land on something that is technically traversable by the entity but it doesn't
|
||||
// fit the intention of the task. Example, a little bird wandering might end up finishing on a flight node,
|
||||
// but it doesn't really want to fly in place so it'd prefer not ending there.
|
||||
while (resolvedPath.endNode?.type?.let { walkTarget.destinationNodeTypeFilter(it) } == false) {
|
||||
resolvedPath.deleteNode(resolvedPath.nodeCount - 1)
|
||||
}
|
||||
if (resolvedPath.nodeCount == 0) {
|
||||
resolvedPath = null
|
||||
}
|
||||
}
|
||||
path = resolvedPath
|
||||
}
|
||||
} else {
|
||||
path = entity.navigation.createPath(target, 0)
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
private fun hasReached(entity: PathfinderMob, walkTarget: WalkTarget): Boolean {
|
||||
return walkTarget.target.currentBlockPosition().distManhattan(entity.blockPosition()) <= walkTarget.closeEnoughDist
|
||||
}
|
||||
|
||||
fun isTargetSpectator(target: WalkTarget): Boolean {
|
||||
val lookTarget = target.target
|
||||
return if (lookTarget is EntityTracker) {
|
||||
lookTarget.entity.isSpectator
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.CobblemonWanderControl.WanderCenter
|
||||
import com.cobblemon.mod.common.api.ai.config.task.WanderTaskConfig.Companion.MAX_LOOK_DOWN_DISTANCE
|
||||
import com.cobblemon.mod.common.entity.OmniPathingEntity
|
||||
import com.cobblemon.mod.common.entity.ai.CobblemonRandomSurfacePos
|
||||
import com.cobblemon.mod.common.entity.ai.CobblemonWalkTarget
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.sqrt
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorUtils
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.entity.ai.util.HoverRandomPos
|
||||
import net.minecraft.world.entity.ai.util.LandRandomPos
|
||||
import net.minecraft.world.level.material.Fluids
|
||||
import net.minecraft.world.level.pathfinder.PathType
|
||||
|
||||
/**
|
||||
* A type of wandering behaviour for an entity. I'm not sure if we keep this.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 29th, 2025
|
||||
*/
|
||||
enum class WanderType(
|
||||
val isValid: (PathfinderMob) -> Boolean,
|
||||
val choosePosition: (PathfinderMob, minimumHeight: Int, maximumHeight: Int, horizontalRange: Int, verticalRange: Int) -> BlockPos?,
|
||||
val createWalkTarget: (PathfinderMob, position: BlockPos, avoidsTargetingAir: Boolean, speedMultiplier: Float) -> WalkTarget?,
|
||||
) {
|
||||
|
||||
WATER(
|
||||
isValid = { it.isInWater },
|
||||
choosePosition = choosePosition@{ entity, _, _, horizontalRange, verticalRange ->
|
||||
var pos = BehaviorUtils.getRandomSwimmablePos(entity, horizontalRange, verticalRange)?.let(BlockPos::containing)
|
||||
?: return@choosePosition null
|
||||
|
||||
// Move target pos down so that we don't move out of water too much
|
||||
val requiredDepth = ceil(0.5 + entity.eyeHeight)
|
||||
// Get the current depth of the block
|
||||
var depth = 1
|
||||
var testPos = pos.above()
|
||||
var blockState = entity.level().getBlockState(testPos)
|
||||
while (blockState.fluidState.type == Fluids.WATER) {
|
||||
depth++
|
||||
testPos = testPos!!.above()
|
||||
blockState = entity.level().getBlockState(testPos)
|
||||
}
|
||||
|
||||
if (depth < requiredDepth) {
|
||||
// Iterate down until we reach the desired min depth or we reach a non water block
|
||||
pos = pos.below()
|
||||
blockState = entity.level().getBlockState(pos)
|
||||
while (blockState.fluidState.type == Fluids.WATER && depth < requiredDepth && pos.y > entity.level().minBuildHeight) {
|
||||
depth++
|
||||
pos = pos.below()
|
||||
blockState = entity.level().getBlockState(pos)
|
||||
}
|
||||
}
|
||||
|
||||
return@choosePosition if (depth < requiredDepth) null else pos
|
||||
},
|
||||
createWalkTarget = { _, pos, _, speedMultiplier ->
|
||||
CobblemonWalkTarget(
|
||||
pos = pos,
|
||||
nodeTypeFilter = { it == PathType.WATER || it == PathType.WATER_BORDER },
|
||||
speedModifier = speedMultiplier,
|
||||
completionRange = 0
|
||||
)
|
||||
}
|
||||
),
|
||||
LAND(
|
||||
isValid = { entity -> !entity.isInWater && !entity.isInLava },
|
||||
choosePosition = choosePosition@{ entity, minimumHeight, maximumHeight, horizontalRange, verticalRange ->
|
||||
val targetVec = when {
|
||||
maximumHeight != -1 -> {
|
||||
HoverRandomPos.getPos(
|
||||
entity,
|
||||
horizontalRange,
|
||||
verticalRange,
|
||||
entity.random.nextFloat() - 0.5,
|
||||
entity.random.nextFloat() - 0.5,
|
||||
Math.PI.toFloat(),
|
||||
maximumHeight,
|
||||
minimumHeight
|
||||
)
|
||||
}
|
||||
entity.isUnderWater && entity.canBreatheUnderwater() && !((entity as OmniPathingEntity).canSwimInWater()) -> {
|
||||
BehaviorUtils.getRandomSwimmablePos(
|
||||
entity,
|
||||
horizontalRange,
|
||||
verticalRange
|
||||
)
|
||||
}
|
||||
entity is OmniPathingEntity && (entity.canWalkOnWater() || entity.canWalkOnLava()) -> {
|
||||
CobblemonRandomSurfacePos.getPos(
|
||||
entity,
|
||||
horizontalRange,
|
||||
verticalRange
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
LandRandomPos.getPos(
|
||||
entity,
|
||||
horizontalRange,
|
||||
verticalRange
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val pos = targetVec?.let(BlockPos::containing) ?: return@choosePosition null
|
||||
LAND.applyHeightConstraints(pos, minimumHeight, maximumHeight, entity.level() as ServerLevel)
|
||||
},
|
||||
createWalkTarget = { entity, pos, avoidsTargetingAir, speedMultiplier ->
|
||||
CobblemonWalkTarget(
|
||||
pos = pos,
|
||||
speedModifier = speedMultiplier,
|
||||
completionRange = 0,
|
||||
nodeTypeFilter = { nodeType ->
|
||||
entity.canBreatheUnderwater() || nodeType !in listOf(
|
||||
PathType.WATER,
|
||||
PathType.WATER_BORDER
|
||||
)
|
||||
},
|
||||
destinationNodeTypeFilter = { nodeType ->
|
||||
!avoidsTargetingAir || nodeType !in listOf(
|
||||
PathType.OPEN
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
;
|
||||
|
||||
fun generateWalkTarget(
|
||||
entity: PathfinderMob,
|
||||
maxAttempts: Int,
|
||||
center: WanderCenter?,
|
||||
minimumHeight: Int,
|
||||
maximumHeight: Int,
|
||||
horizontalRange: Int,
|
||||
verticalRange: Int,
|
||||
avoidTargetingAir: Boolean,
|
||||
speedMultiplier: Float
|
||||
): WalkTarget? {
|
||||
var attempts = 0
|
||||
var pos: BlockPos? = null
|
||||
|
||||
while (attempts++ < maxAttempts && pos == null) {
|
||||
pos = choosePosition(entity, minimumHeight, maximumHeight, horizontalRange, verticalRange)
|
||||
?: return null
|
||||
if (!isSuitable(center, pos)) {
|
||||
pos = null
|
||||
}
|
||||
}
|
||||
|
||||
if (pos == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
return createWalkTarget(entity, pos, avoidTargetingAir, speedMultiplier)
|
||||
}
|
||||
|
||||
private fun isSuitable(center: WanderCenter?, position: BlockPos): Boolean {
|
||||
val center = center ?: return true
|
||||
val centerPos = BlockPos(center.x.toInt(), center.y.toInt(), center.z.toInt())
|
||||
val distance = sqrt(centerPos.distSqr(position))
|
||||
val suitable = distance >= center.minRange && distance <= center.maxRange
|
||||
return suitable
|
||||
}
|
||||
|
||||
private fun applyHeightConstraints(
|
||||
pos: BlockPos,
|
||||
minimumHeight: Int,
|
||||
maximumHeight: Int,
|
||||
world: ServerLevel
|
||||
): BlockPos {
|
||||
if (minimumHeight <= 0 && maximumHeight == -1) {
|
||||
return pos // It ain't a hoverer
|
||||
}
|
||||
|
||||
val block = world.getBlockState(pos)
|
||||
val altitude = if (!block.isAir) {
|
||||
0
|
||||
} else {
|
||||
(1..MAX_LOOK_DOWN_DISTANCE).firstOrNull {
|
||||
val newPos = pos.below(it)
|
||||
if (!world.getBlockState(newPos).isAir) {
|
||||
return@firstOrNull true
|
||||
} else if (newPos.y <= world.minBuildHeight) {
|
||||
// Don't adjust downward into the void (Mostly if we're in the end)
|
||||
// This doesn't stop fliers from wandering off end islands,
|
||||
// but it does stop them from diving directly into the void.
|
||||
return pos
|
||||
}
|
||||
return@firstOrNull false
|
||||
} ?: MAX_LOOK_DOWN_DISTANCE
|
||||
}
|
||||
|
||||
if (altitude > maximumHeight && maximumHeight >= 0) {
|
||||
val excess = altitude - maximumHeight
|
||||
val excessFromMinimum = altitude - minimumHeight
|
||||
val correction = world.random.nextIntBetweenInclusive(excess, excessFromMinimum)
|
||||
return pos.atY(pos.y - correction)
|
||||
} else if (altitude < minimumHeight && minimumHeight >= 0) {
|
||||
val deficit = minimumHeight - altitude
|
||||
val deficitFromMaximum = maximumHeight - altitude
|
||||
val correction = world.random.nextIntBetweenInclusive(deficit, deficitFromMaximum)
|
||||
return pos.atY(pos.y + correction)
|
||||
} else {
|
||||
return pos
|
||||
}
|
||||
}
|
||||
}
|
||||
-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.api.ai.biggerbrain.distraction
|
||||
|
||||
import net.minecraft.world.damagesource.DamageSource
|
||||
|
||||
/**
|
||||
* Something that may distract an entity from its current fixation. The majority of fixations
|
||||
* will rely on the types of distraction to determine if they should be distracted.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 29th, 2025
|
||||
*/
|
||||
open class Distraction(val types: Set<DistractionType>) {
|
||||
constructor(vararg types: DistractionType) : this(types.toSet())
|
||||
|
||||
val isIdleBoredom = DistractionType.IDLE_BOREDOM in types
|
||||
val isForce = DistractionType.FORCE in types
|
||||
val isComfort = DistractionType.COMFORT in types
|
||||
val isDamage = DistractionType.DAMAGE in types
|
||||
|
||||
fun hasAnyOf(vararg distractionTypes: DistractionType): Boolean {
|
||||
return distractionTypes.any { it in types }
|
||||
}
|
||||
|
||||
companion object {
|
||||
val FORCE = Distraction(DistractionType.FORCE)
|
||||
}
|
||||
}
|
||||
|
||||
/** Reusable basic distraction for a COMFORT type of distraction. */
|
||||
val comfortDistraction = Distraction(DistractionType.COMFORT)
|
||||
/** Reusable basic distraction for an IDLE_BOREDOM type of distraction. */
|
||||
val idleBoredomDistraction = Distraction(DistractionType.IDLE_BOREDOM)
|
||||
|
||||
open class HurtDistraction(val damageSource: DamageSource) : Distraction(DistractionType.DAMAGE)
|
||||
-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.api.ai.biggerbrain.distraction
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.EntityFixation
|
||||
|
||||
/**
|
||||
* A categorisation of distractions that can be attempted on an [EntityFixation].
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 29th, 2025
|
||||
*/
|
||||
enum class DistractionType {
|
||||
/** Represents a distraction that the entity is not particularly motivated by but would consider doing out of boredom. */
|
||||
IDLE_BOREDOM,
|
||||
/** Represents a distraction that is for the sake of the entity's comfort because it isn't comfortable where it is. */
|
||||
COMFORT,
|
||||
/** Represents a distraction motivated by being hurt. */
|
||||
DAMAGE,
|
||||
/** A forceful distraction. Just about everything should respect this but it's conceivable that something not. */
|
||||
FORCE,
|
||||
}
|
||||
-161
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain.fixation
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.BiggerBrain
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.LookingTracker
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.MovementStatus
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.MovementTracker
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.RegularMovementTracker
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.Distraction
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.DistractionType
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.ai.moves.RealTimeMove
|
||||
import com.cobblemon.mod.common.pokemon.ai.moves.RealTimeMoveInstance
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.mainThreadRuntime
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.EntityTracker
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import kotlin.collections.set
|
||||
|
||||
class AttackFixation(
|
||||
val targetEntity: LivingEntity,
|
||||
/** Distraction types that will be respected. */
|
||||
private val speedMultiplier: Expression = "1.0".asExpression(),
|
||||
private val availableMoves: List<RealTimeMove> = emptyList(),
|
||||
val distractionTypes: Set<DistractionType>,
|
||||
) : EntityFixation {
|
||||
|
||||
private val globalAttackCooldownTicks: Int = 20 // TODO: pull from pokemon stats
|
||||
var movementTracker: MovementTracker? = null
|
||||
var lookingTracker: LookingTracker? = null
|
||||
var activeMoveInstance: RealTimeMoveInstance? = null
|
||||
override fun getDescription(entity: LivingEntity): String {
|
||||
return "Attacking Target"
|
||||
}
|
||||
|
||||
override fun canDistract(distraction: Distraction, entity: LivingEntity): Boolean {
|
||||
return distraction.types.any(distractionTypes::contains)
|
||||
}
|
||||
|
||||
override fun tick(entity: LivingEntity, brain: BiggerBrain): Boolean {
|
||||
if (entity !is PokemonEntity || !entity.isAlive) return false
|
||||
entity as PokemonEntity // Intellij and my brain says this is redundant but I'm not getting smart casting later on sooo
|
||||
val targetedEntity = brain.getMemory(MemoryModuleType.ATTACK_TARGET)
|
||||
?: return false
|
||||
|
||||
if (targetedEntity.isRemoved || targetedEntity.isDeadOrDying || brain.getMemory(MemoryModuleType.AVOID_TARGET) != null) {
|
||||
brain.eraseMemory(MemoryModuleType.ATTACK_TARGET)
|
||||
brain.eraseMemory(MemoryModuleType.ANGRY_AT)
|
||||
return false
|
||||
}
|
||||
|
||||
if (targetedEntity is Player && (targetedEntity.isCreative || targetedEntity.isSpectator)) {
|
||||
brain.eraseMemory(MemoryModuleType.ATTACK_TARGET)
|
||||
brain.eraseMemory(MemoryModuleType.ANGRY_AT)
|
||||
return false
|
||||
}
|
||||
|
||||
// If we have a current target, check if it's still valid and within roam range (if tethered)
|
||||
if (targetedEntity.isAlive) {
|
||||
val tethering = (entity).tethering
|
||||
if (tethering != null && !tethering.canRoamTo(targetedEntity.blockPosition())) {
|
||||
// Target moved out of range let's kill the memory >:)
|
||||
brain.distract(Distraction.FORCE)
|
||||
entity.brain.eraseMemory(MemoryModuleType.ATTACK_TARGET)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if (activeMoveInstance != null && activeMoveInstance!!.completed) {
|
||||
activeMoveInstance = null
|
||||
}
|
||||
|
||||
var runtime = mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
runtime = runtime.withQueryValue("target", targetedEntity.asMostSpecificMoLangValue())
|
||||
val speed = runtime.resolveFloat(speedMultiplier)
|
||||
|
||||
var selectedMoveIndex = -1
|
||||
var distanceToTarget = -1.0f
|
||||
|
||||
if (!(entity.biggerBrain.getMemory(MemoryModuleType.ATTACK_COOLING_DOWN) ?: false)) {
|
||||
// Not blocked by global cooldown, check if any available moves can be performed
|
||||
var highestPriority = Int.MAX_VALUE
|
||||
distanceToTarget = entity.distanceTo(targetedEntity)
|
||||
availableMoves.forEachIndexed { index, move ->
|
||||
// check for cooldown ticks, priority, and range
|
||||
// TODO: Account for hitbox sizes when doing range checks
|
||||
if (move.id !in entity.pokemon.realTimeMoveCooldowns && move.priority < highestPriority
|
||||
&& (distanceToTarget <= move.maxRange || entity.isWithinMeleeAttackRange(targetedEntity))
|
||||
&& (distanceToTarget >= move.minRange)
|
||||
) {
|
||||
selectedMoveIndex = index
|
||||
highestPriority = move.priority
|
||||
}
|
||||
}
|
||||
if (selectedMoveIndex != -1) {
|
||||
val selectedMove = availableMoves[selectedMoveIndex]
|
||||
activeMoveInstance = selectedMove.createInstance(entity, targetedEntity)
|
||||
activeMoveInstance?.start()
|
||||
// Reset cooldowns
|
||||
entity.pokemon.realTimeMoveCooldowns[selectedMove.id] = selectedMove.cooldownTicks
|
||||
brain.setMemory(MemoryModuleType.ATTACK_COOLING_DOWN, true, globalAttackCooldownTicks.toLong())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (lookingTracker != null) {
|
||||
lookingTracker!!.tick()
|
||||
}
|
||||
|
||||
if (movementTracker != null) {
|
||||
val movementStatus = movementTracker!!.tick()
|
||||
if (movementStatus != MovementStatus.PENDING) {
|
||||
movementTracker!!.stop()
|
||||
movementTracker = null
|
||||
}
|
||||
} else {
|
||||
// Not moving right now and we need to figure out to what distance to the enemy we want to move to
|
||||
var idealDistanceToTarget = Float.MAX_VALUE
|
||||
var highestPriority = Int.MAX_VALUE
|
||||
availableMoves.forEachIndexed { index, move ->
|
||||
// We want the highest priority move that's not on cooldown
|
||||
if (move.id !in entity.pokemon.realTimeMoveCooldowns && move.priority < highestPriority) {
|
||||
highestPriority = move.priority
|
||||
idealDistanceToTarget = move.maxRange
|
||||
}
|
||||
}
|
||||
|
||||
// Get distance to target if we didn't initialize it in the earlier block
|
||||
if (distanceToTarget < 0) {
|
||||
distanceToTarget = entity.distanceTo(targetedEntity)
|
||||
}
|
||||
if (idealDistanceToTarget < distanceToTarget) {
|
||||
val walkTarget = WalkTarget(EntityTracker(targetedEntity, true), speed, idealDistanceToTarget.toInt())
|
||||
movementTracker = RegularMovementTracker.attempt(entity, walkTarget)
|
||||
lookingTracker = LookingTracker.forTargetEntity(entity, targetedEntity, trackEyeHeight = true)
|
||||
} else if (lookingTracker == null) {
|
||||
// Fixate at looking at the target so we don't wander off
|
||||
lookingTracker = LookingTracker.forTargetEntity(entity, targetedEntity, trackEyeHeight = true)
|
||||
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain.fixation
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.BiggerBrain
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.Distraction
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
/**
|
||||
* A fixation that rejects all non-force distractions and does nothing, lasting until
|
||||
* the provided [condition] is no longer true.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since January 16th, 2026
|
||||
*/
|
||||
open class ConditionalLockFixation(
|
||||
val description: String,
|
||||
val condition: () -> Boolean
|
||||
): EntityFixation, LockFixation {
|
||||
override fun canDistract(distraction: Distraction, entity: LivingEntity) = distraction.isForce
|
||||
override fun getDescription(entity: LivingEntity) = description
|
||||
override fun tick(entity: LivingEntity, brain: BiggerBrain) = condition()
|
||||
}
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain.fixation
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.BiggerBrain
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.Distraction
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
/**
|
||||
* A fixation that rejects all non-force distractions and does nothing for some
|
||||
* number of ticks.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since January 16th, 2026
|
||||
*/
|
||||
open class DurationLockFixation(
|
||||
val description: String,
|
||||
var durationTicks: Int
|
||||
) : EntityFixation, LockFixation {
|
||||
override fun canDistract(distraction: Distraction, entity: LivingEntity) = distraction.isForce
|
||||
override fun getDescription(entity: LivingEntity) = description.replace("{ticks}", durationTicks.toString())
|
||||
override fun tick(entity: LivingEntity, brain: BiggerBrain): Boolean {
|
||||
return --durationTicks > 0
|
||||
}
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain.fixation
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.BiggerBrain
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.Distraction
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
/**
|
||||
* An entity's fixation, representing a task that takes a central role in the entity's behaviour
|
||||
* and excludes all other possible fixations.
|
||||
*
|
||||
* The role of the fixation is to do an action which is the primary focus of the entity at that time,
|
||||
* and which may be distracted from under some circumstances. An entity may be fixated on moving from
|
||||
* A to B, and then be distracted upon being hurt. Or maybe it's an attack fixation, in which case
|
||||
* damage doesn't distract it at all.
|
||||
*
|
||||
* The difference between a fixation and an objective is that objectives are capable of running in parallel,
|
||||
* and a fixation may even be in the pursuit of an objective, but the fixation is central.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 28th, 2025
|
||||
*/
|
||||
interface EntityFixation {
|
||||
/** Returns true if the given distraction can stop this fixation. */
|
||||
fun canDistract(distraction: Distraction, entity: LivingEntity): Boolean
|
||||
/** Notifies the fixation that it has been distracted by the given distraction so it can do clean up. */
|
||||
fun onDistract(distraction: Distraction, entity: LivingEntity) {}
|
||||
/** Continues doing whatever the fixation does. Returns true if the fixation should continue. */
|
||||
fun tick(entity: LivingEntity, brain: BiggerBrain): Boolean
|
||||
/** Gets a current description of the fixation for the debug screen. */
|
||||
fun getDescription(entity: LivingEntity): String
|
||||
}
|
||||
-18
@@ -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.api.ai.biggerbrain.fixation
|
||||
|
||||
/**
|
||||
* Represents a fixation that blocks battling, capture, etc. for Pokémon. This is
|
||||
* used to control the isBusy property on Pokémon.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since January 16th, 2026
|
||||
*/
|
||||
interface LockFixation
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain.fixation
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.BiggerBrain
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.LookingTracker
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.Distraction
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.DistractionType
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
|
||||
class LookAndLockFixation(
|
||||
override val lookingTracker: LookingTracker?,
|
||||
/** Distraction types that will be respected. */
|
||||
val distractionTypes: Set<DistractionType>,
|
||||
val condition: () -> Boolean
|
||||
) : EntityFixation, LookingTrackerFixation {
|
||||
|
||||
|
||||
override fun getDescription(entity: LivingEntity): String {
|
||||
return "Looking at a nearby entity (Locked)"
|
||||
}
|
||||
|
||||
override fun canDistract(distraction: Distraction, entity: LivingEntity): Boolean {
|
||||
return distraction.types.any(distractionTypes::contains)
|
||||
}
|
||||
|
||||
override fun tick(entity: LivingEntity, brain: BiggerBrain): Boolean {
|
||||
val targetEntity = lookingTracker?.entity ?: return false
|
||||
if ((targetEntity.isRemoved) || entity !is PathfinderMob) {
|
||||
return false
|
||||
}
|
||||
val lookingTracker = lookingTracker
|
||||
lookingTracker.tick()
|
||||
return condition()
|
||||
}
|
||||
}
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain.fixation
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.BiggerBrain
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.LookingTracker
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.MovementStatus
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.MovementTracker
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.Distraction
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.DistractionType
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
/**
|
||||
* A simple fixation that uses both a looking tracker and a movement tracker.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 29th, 2025
|
||||
*/
|
||||
open class LookAndMoveFixation(
|
||||
/** Distraction types that will be respected. */
|
||||
val distractionTypes: Set<DistractionType>,
|
||||
/** How to describe the fixation in the debug overlay. */
|
||||
val description: String,
|
||||
override val lookingTracker: LookingTracker,
|
||||
override val movementTracker: MovementTracker,
|
||||
val onMovementComplete: ((entity: LivingEntity, brain: BiggerBrain) -> Unit)? = null
|
||||
): EntityFixation, LookingTrackerFixation, MovementTrackerFixation {
|
||||
override fun getDescription(entity: LivingEntity) = description
|
||||
|
||||
override fun canDistract(distraction: Distraction, entity: LivingEntity): Boolean {
|
||||
return distraction.types.any(distractionTypes::contains)
|
||||
}
|
||||
|
||||
override fun onDistract(distraction: Distraction, entity: LivingEntity) {
|
||||
movementTracker.stop()
|
||||
}
|
||||
|
||||
override fun tick(entity: LivingEntity, brain: BiggerBrain): Boolean {
|
||||
lookingTracker.tick()
|
||||
val continueFixation = tickMovementFixation() == MovementStatus.PENDING
|
||||
if (!continueFixation && onMovementComplete != null) {
|
||||
onMovementComplete.invoke(entity, brain)
|
||||
}
|
||||
return continueFixation
|
||||
}
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain.fixation
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.LookingTracker
|
||||
|
||||
/**
|
||||
* Applied to fixations which may have looking associated with them. This is useful
|
||||
* in the case that an objective needs to know if the current fixation intends on (or is)
|
||||
* controlling their looking direction.
|
||||
*
|
||||
* Example: An objective that makes Pokémon bob their heads up and down while music is playing.
|
||||
* Said objective would not warrant a full fixation, but would still like to ensure that the
|
||||
* current fixation does not intend on using a looking tracker.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 29th, 2025
|
||||
*/
|
||||
interface LookingTrackerFixation {
|
||||
val lookingTracker: LookingTracker?
|
||||
}
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain.fixation
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.MovementStatus
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.MovementTracker
|
||||
|
||||
/**
|
||||
* Applied to fixations which may have movement associated with them. This is useful
|
||||
* in the case that an objective needs to know if the current fixation intends on (or is)
|
||||
* controlling their movement.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 29th, 2025
|
||||
*/
|
||||
interface MovementTrackerFixation {
|
||||
/** The movement tracker at the moment. */
|
||||
val movementTracker: MovementTracker?
|
||||
|
||||
/** Ticks the movement tracker in a way that skips finalized movement trackers. */
|
||||
fun tickMovementFixation(): MovementStatus? {
|
||||
val movementTracker = this.movementTracker ?: return null
|
||||
return if (movementTracker.lastStatus != MovementStatus.PENDING) {
|
||||
movementTracker.lastStatus
|
||||
} else {
|
||||
movementTracker.tick()
|
||||
}
|
||||
}
|
||||
}
|
||||
-168
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain.objective
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asSimplifiedExpression
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.BiggerBrain
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.Distraction
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.DistractionType
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.AttackFixation
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.EntityFixation
|
||||
import com.cobblemon.mod.common.api.ai.config.objective.ObjectiveConfig
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.mainThreadRuntime
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
import com.cobblemon.mod.common.util.resolveString
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
|
||||
class AggressiveBehaviour(
|
||||
speedMultiplier: Expression = "0.5".asExpression(), // How do we transfer speed to the attack behaviour? Do we want to?
|
||||
engageRange: Expression = "15.0".asExpression(),
|
||||
disengageRange: Expression = "20.0".asExpression(),
|
||||
condition: Expression = "true".asExpression(), // Self/environment condition check
|
||||
targetCondition: Expression = "true".asExpression(), // target condition (will be checked on entity interaction)
|
||||
description: Expression = "'Aggressive Behaviour'".asExpression(),
|
||||
val maxAttackDuration: Expression = "300".asExpression(),
|
||||
) : EntityResponseObjective(
|
||||
speedMultiplier = speedMultiplier, // How do we transfer speed to the attack behaviour? Do we want to?
|
||||
engageRange = engageRange,
|
||||
disengageRange = disengageRange,
|
||||
condition = condition, // Self/environment condition check
|
||||
targetCondition = targetCondition, // target condition (will be checked on entity interaction)
|
||||
description = description,
|
||||
) {
|
||||
|
||||
private var remainingCooldownTicks = 0
|
||||
private var attackFixation : EntityFixation? = null
|
||||
override val observedMemories = listOf(MemoryModuleType.HURT_BY_ENTITY, CobblemonMemories.ATTACK_TARGET_DATA)
|
||||
|
||||
|
||||
override fun perform(
|
||||
entity: LivingEntity,
|
||||
brain: BiggerBrain,
|
||||
activeObjectiveTags: MutableSet<String>
|
||||
): ObjectiveStatus {
|
||||
if (entity !is PokemonEntity || !entity.isAlive) return ObjectiveStatus.INVALID
|
||||
if (brain.getMemory(MemoryModuleType.AVOID_TARGET) != null) {
|
||||
return ObjectiveStatus.BLOCKED
|
||||
}
|
||||
val attackTarget = brain.getMemory(MemoryModuleType.ATTACK_TARGET)
|
||||
if (trackedEntity != null) {
|
||||
// has active target
|
||||
if (attackTarget != null && trackedEntity?.uuid == attackTarget.uuid) {
|
||||
// Check if we continue
|
||||
if (shouldContinue(entity, brain)) {
|
||||
return ObjectiveStatus.ACTIVE
|
||||
} else {
|
||||
brain.distract(Distraction.FORCE)
|
||||
attackFixation = null
|
||||
brain.eraseMemory(MemoryModuleType.ATTACK_TARGET)
|
||||
brain.eraseMemory(CobblemonMemories.ATTACK_TARGET_DATA)
|
||||
return ObjectiveStatus.INACTIVE
|
||||
}
|
||||
} else {
|
||||
// Something has overridden us and independently set the attack target
|
||||
trackedEntity = null
|
||||
attackFixation = null
|
||||
return ObjectiveStatus.BLOCKED
|
||||
}
|
||||
} else {
|
||||
// No active target
|
||||
if (remainingCooldownTicks > 0) {
|
||||
remainingCooldownTicks--
|
||||
return ObjectiveStatus.INACTIVE
|
||||
} else {
|
||||
remainingCooldownTicks = 20
|
||||
}
|
||||
val targetEntity = scanForValidTargets(entity, brain)
|
||||
if (targetEntity != null && brain.distract(Distraction.FORCE)) {
|
||||
val runtime = mainThreadRuntime
|
||||
val attackDuration = runtime.resolveInt(maxAttackDuration)
|
||||
trackedEntity = targetEntity
|
||||
brain.setMemory(MemoryModuleType.ATTACK_TARGET, targetEntity, attackDuration.toLong())
|
||||
attackFixation = brain.fixate(
|
||||
AttackFixation(
|
||||
targetEntity = trackedEntity!!,
|
||||
speedMultiplier = speedMultiplier,
|
||||
distractionTypes = setOf(DistractionType.FORCE),
|
||||
availableMoves = getRealTimeMoves(entity)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
return if (trackedEntity != null) ObjectiveStatus.ACTIVE else ObjectiveStatus.INACTIVE
|
||||
}
|
||||
|
||||
override fun onRegister(entity: LivingEntity, brain: BiggerBrain) {
|
||||
brain.subscribe(
|
||||
priority = Priority.LOW,
|
||||
memory = CobblemonMemories.ATTACK_TARGET_DATA
|
||||
) { attackData, labels ->
|
||||
val targetEntity = brain.getMemory(MemoryModuleType.ATTACK_TARGET) ?: return@subscribe true
|
||||
if (trackedEntity?.uuid == targetEntity.uuid) {
|
||||
// We smacked them, refresh our attack timer
|
||||
val runtime = mainThreadRuntime.withQueryValue("entity", (targetEntity).asMostSpecificMoLangValue())
|
||||
val attackDuration = runtime.resolveInt(maxAttackDuration)
|
||||
brain.setMemory(MemoryModuleType.ATTACK_TARGET, targetEntity, attackDuration.toLong())
|
||||
}
|
||||
return@subscribe true
|
||||
}
|
||||
}
|
||||
|
||||
class Config : ObjectiveConfig {
|
||||
val speedMultiplier: ExpressionOrEntityVariable = Either.left("0.5".asExpression())
|
||||
val engageRange: ExpressionOrEntityVariable = Either.left("15.0".asExpression())
|
||||
val disengageRange: ExpressionOrEntityVariable = Either.left("20.0".asExpression())
|
||||
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
val targetCondition: ExpressionOrEntityVariable = Either.left("false".asExpression())
|
||||
val maxAttackDuration: ExpressionOrEntityVariable = Either.left("300".asExpression())
|
||||
val description: ExpressionOrEntityVariable = Either.left("'Aggressive Behaviour'".asExpression())
|
||||
override fun getVariables(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): List<MoLangConfigVariable> {
|
||||
return listOf(
|
||||
condition,
|
||||
targetCondition,
|
||||
speedMultiplier,
|
||||
engageRange,
|
||||
disengageRange,
|
||||
maxAttackDuration,
|
||||
description
|
||||
).asVariables()
|
||||
}
|
||||
|
||||
override fun create(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): Objective {
|
||||
return AggressiveBehaviour(
|
||||
condition = condition.asSimplifiedExpression(entity),
|
||||
targetCondition = targetCondition.asSimplifiedExpression(entity),
|
||||
speedMultiplier = speedMultiplier.asSimplifiedExpression(entity),
|
||||
engageRange = engageRange.asSimplifiedExpression(entity),
|
||||
disengageRange = disengageRange.asSimplifiedExpression(entity),
|
||||
maxAttackDuration = maxAttackDuration.asSimplifiedExpression(entity),
|
||||
description = description.asSimplifiedExpression(entity)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
-170
@@ -1,170 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain.objective
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.CobblemonAttackTargetData
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asSimplifiedExpression
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.BiggerBrain
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.LookingTracker
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.RegularMovementTracker
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.Distraction
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.DistractionType
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.EntityFixation
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.LookAndMoveFixation
|
||||
import com.cobblemon.mod.common.api.ai.config.objective.ObjectiveConfig
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.mainThreadRuntime
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.EntityTracker
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.entity.player.Player
|
||||
|
||||
class AttackTargetMelee(
|
||||
private val speedMultiplier: Expression = "1.0".asExpression(),
|
||||
private val attackRange: Expression = "2.0".asExpression(),
|
||||
private val attackCooldownTicks: Int = 20
|
||||
) : Objective {
|
||||
private var movementTask: EntityFixation? = null
|
||||
private var remainingCooldownTicks = 0
|
||||
|
||||
override val observedMemories = listOf(MemoryModuleType.ATTACK_TARGET)
|
||||
|
||||
override fun getDescription(entity: LivingEntity) = "Attack target melee"
|
||||
|
||||
override fun perform(
|
||||
entity: LivingEntity,
|
||||
brain: BiggerBrain,
|
||||
activeObjectiveTags: MutableSet<String>
|
||||
): ObjectiveStatus {
|
||||
if (entity !is PokemonEntity || !entity.isAlive) return ObjectiveStatus.INVALID
|
||||
|
||||
val target = brain.getMemory(MemoryModuleType.ATTACK_TARGET)
|
||||
?: return ObjectiveStatus.INACTIVE
|
||||
|
||||
if (target.isRemoved || target.isDeadOrDying) {
|
||||
brain.eraseMemory(MemoryModuleType.ATTACK_TARGET)
|
||||
brain.eraseMemory(MemoryModuleType.ANGRY_AT)
|
||||
return ObjectiveStatus.INACTIVE
|
||||
}
|
||||
|
||||
if (target is Player && (target.isCreative || target.isSpectator)) {
|
||||
brain.eraseMemory(MemoryModuleType.ATTACK_TARGET)
|
||||
brain.eraseMemory(MemoryModuleType.ANGRY_AT)
|
||||
return ObjectiveStatus.INACTIVE
|
||||
}
|
||||
|
||||
if (remainingCooldownTicks > 0) {
|
||||
remainingCooldownTicks--
|
||||
}
|
||||
|
||||
val runtime = mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
val range = runtime.resolveFloat(attackRange)
|
||||
val speed = runtime.resolveFloat(speedMultiplier)
|
||||
|
||||
// This is melee thing, but not everything will do melee in the future
|
||||
if (entity.distanceToSqr(target) <= range * range && entity.hasLineOfSight(target)) {
|
||||
if (remainingCooldownTicks <= 0) {
|
||||
if (entity.doHurtTarget(target)) {
|
||||
entity.swing(InteractionHand.MAIN_HAND)
|
||||
var attackTargetData = brain.getMemory(CobblemonMemories.ATTACK_TARGET_DATA)
|
||||
if (attackTargetData != null) {
|
||||
attackTargetData.hitsLanded += 1
|
||||
|
||||
} else {
|
||||
attackTargetData = CobblemonAttackTargetData()
|
||||
attackTargetData.hitsLanded = 1
|
||||
}
|
||||
brain.setMemory(CobblemonMemories.ATTACK_TARGET_DATA, attackTargetData)
|
||||
}
|
||||
remainingCooldownTicks = attackCooldownTicks
|
||||
}
|
||||
return ObjectiveStatus.ACTIVE
|
||||
}
|
||||
|
||||
// If we have a current target, check if it's still valid and within roam range (if tethered)
|
||||
if (target.isAlive) {
|
||||
val tethering = (entity).tethering
|
||||
if (tethering != null && !tethering.canRoamTo(target.blockPosition())) {
|
||||
// Target moved out of range let's kill the memory >:)
|
||||
brain.distract(Distraction.FORCE)
|
||||
entity.brain.eraseMemory(MemoryModuleType.ATTACK_TARGET)
|
||||
}
|
||||
}
|
||||
|
||||
if (brain.isFixation(movementTask)) {
|
||||
return ObjectiveStatus.FIXATED
|
||||
}
|
||||
|
||||
if (!brain.distract(Distraction.FORCE)) return ObjectiveStatus.BLOCKED
|
||||
val walkTarget = WalkTarget(EntityTracker(target, true), speed, 1)
|
||||
val movementTracker = RegularMovementTracker.attempt(entity, walkTarget) ?: return ObjectiveStatus.ACTIVE
|
||||
movementTask = brain.fixate(LookAndMoveFixation(
|
||||
distractionTypes = setOf(DistractionType.FORCE),
|
||||
lookingTracker = LookingTracker.forTargetEntity(entity, target, trackEyeHeight = true),
|
||||
movementTracker = movementTracker,
|
||||
description = "Moving to attack target"))
|
||||
return ObjectiveStatus.FIXATED
|
||||
}
|
||||
|
||||
override fun onRegister(entity: LivingEntity, brain: BiggerBrain) {
|
||||
brain.subscribe(
|
||||
priority = Priority.LOW,
|
||||
memory = MemoryModuleType.ATTACK_TARGET
|
||||
) { value, labels ->
|
||||
if (value == null) {
|
||||
if (brain.isFixation(movementTask)) {
|
||||
brain.distract(Distraction.FORCE)
|
||||
movementTask = null
|
||||
}
|
||||
}
|
||||
return@subscribe true
|
||||
}
|
||||
}
|
||||
|
||||
class Config : ObjectiveConfig {
|
||||
val speedMultiplier: ExpressionOrEntityVariable = Either.left("1.0".asExpression())
|
||||
val attackRange: ExpressionOrEntityVariable = Either.left("2.0".asExpression())
|
||||
val attackCooldownTicks: ExpressionOrEntityVariable = Either.left("20".asExpression())
|
||||
|
||||
override fun getVariables(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): List<MoLangConfigVariable> {
|
||||
return listOf(speedMultiplier, attackRange, attackCooldownTicks).asVariables()
|
||||
}
|
||||
|
||||
override fun create(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): Objective {
|
||||
return AttackTargetMelee(
|
||||
speedMultiplier = speedMultiplier.asSimplifiedExpression(entity),
|
||||
attackRange = attackRange.asSimplifiedExpression(entity),
|
||||
attackCooldownTicks = behaviourConfigurationContext.runtime.resolveInt(
|
||||
attackCooldownTicks.asSimplifiedExpression(entity)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
-173
@@ -1,173 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain.objective
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asSimplifiedExpression
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.BiggerBrain
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.LookingTracker
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.RegularMovementTracker
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.Distraction
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.DistractionType
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.ConditionalLockFixation
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.EntityFixation
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.LookAndMoveFixation
|
||||
import com.cobblemon.mod.common.api.ai.config.objective.ObjectiveConfig
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonBlockTags
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.mainThreadRuntime
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.sendParticlesServer
|
||||
import com.cobblemon.mod.common.util.toVec3d
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.particles.ParticleTypes
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.entity.ai.util.LandRandomPos
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class AvoidScarekrow(
|
||||
private val speedMultiplier: Expression = "0.5".asExpression(),
|
||||
) : Objective {
|
||||
private var movementTask: EntityFixation? = null
|
||||
private var remainingCooldownTicks = 0
|
||||
|
||||
override val observedMemories = listOf(CobblemonMemories.NEARBY_SCAREKROW)
|
||||
|
||||
override fun getDescription(entity: LivingEntity) = "Avoiding target block"
|
||||
|
||||
override fun perform(
|
||||
entity: LivingEntity,
|
||||
brain: BiggerBrain,
|
||||
activeObjectiveTags: MutableSet<String>
|
||||
): ObjectiveStatus {
|
||||
if (entity !is PokemonEntity || !entity.isAlive) return ObjectiveStatus.INVALID
|
||||
|
||||
val target = brain.getMemory(CobblemonMemories.NEARBY_SCAREKROW)
|
||||
?: return ObjectiveStatus.INACTIVE
|
||||
|
||||
// if the scarekrow is gone we dont need to be scared anymore
|
||||
if (!entity.level().getBlockState(target).`is`(CobblemonBlockTags.SCAREKROWS)) {
|
||||
brain.eraseMemory(CobblemonMemories.NEARBY_SCAREKROW)
|
||||
return ObjectiveStatus.INACTIVE
|
||||
}
|
||||
|
||||
// finish existing movement task
|
||||
if (brain.isFixation(movementTask)) {
|
||||
return ObjectiveStatus.FIXATED
|
||||
}
|
||||
|
||||
// aggro against the player should take priority
|
||||
if (brain.getMemory(MemoryModuleType.ATTACK_TARGET) != null) {
|
||||
return ObjectiveStatus.BLOCKED
|
||||
}
|
||||
|
||||
if (remainingCooldownTicks > 0) {
|
||||
remainingCooldownTicks--
|
||||
}
|
||||
val runtime = mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
val speed = runtime.resolveFloat(speedMultiplier)
|
||||
|
||||
if (!brain.distract(Distraction.FORCE)) return ObjectiveStatus.BLOCKED
|
||||
var targetPos : BlockPos? = null
|
||||
|
||||
// fixate on running from the scarekrow until it is out of range
|
||||
brain.fixate(ConditionalLockFixation("Avoiding scarekrow") {
|
||||
brain.getMemory(CobblemonMemories.NEARBY_SCAREKROW) != null
|
||||
})
|
||||
|
||||
// find position
|
||||
val direction = entity.position().subtract(target.toVec3d())
|
||||
for (j in 0..9) {
|
||||
val targetVec3 = LandRandomPos.getPosAway(entity, (Cobblemon.config.scarekrowRadius * 1.5).toInt(), 7, direction)
|
||||
if (targetVec3 != null) {
|
||||
targetPos = BlockPos.containing(targetVec3)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Start a look-and-move fixation only when navigation accepts the selected position.
|
||||
if (targetPos != null) {
|
||||
val movementTracker = RegularMovementTracker.attempt(
|
||||
entity = entity,
|
||||
walkTarget = WalkTarget(
|
||||
targetPos,
|
||||
speed,
|
||||
0
|
||||
)
|
||||
)
|
||||
entity.level().sendParticlesServer(ParticleTypes.HAPPY_VILLAGER, targetPos.above().toVec3d(), 5, Vec3(0.0, 0.0, 0.0), 5.0)
|
||||
if (movementTracker != null) {
|
||||
movementTask = brain.fixate(
|
||||
LookAndMoveFixation(
|
||||
distractionTypes = setOf(
|
||||
DistractionType.FORCE
|
||||
),
|
||||
lookingTracker = LookingTracker.fromNavigationPathOrWalkTarget(
|
||||
entity,
|
||||
movementTracker.walkTarget
|
||||
),
|
||||
movementTracker = movementTracker,
|
||||
description = "Moving away from target block",
|
||||
)
|
||||
)
|
||||
return ObjectiveStatus.FIXATED
|
||||
}
|
||||
}
|
||||
|
||||
return ObjectiveStatus.FIXATED
|
||||
}
|
||||
|
||||
override fun onRegister(entity: LivingEntity, brain: BiggerBrain) {
|
||||
brain.subscribe(
|
||||
priority = Priority.LOW,
|
||||
memory = CobblemonMemories.NEARBY_SCAREKROW,
|
||||
) { value, labels ->
|
||||
if (value == null) {
|
||||
if (brain.isFixation(movementTask)) {
|
||||
brain.distract(Distraction.FORCE)
|
||||
movementTask = null
|
||||
}
|
||||
}
|
||||
return@subscribe true
|
||||
}
|
||||
}
|
||||
|
||||
class Config : ObjectiveConfig {
|
||||
val speedMultiplier: ExpressionOrEntityVariable = Either.left("0.5".asExpression())
|
||||
|
||||
override fun getVariables(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): List<MoLangConfigVariable> {
|
||||
return listOf(speedMultiplier).asVariables()
|
||||
}
|
||||
|
||||
override fun create(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): Objective {
|
||||
return AvoidScarekrow(
|
||||
speedMultiplier = speedMultiplier.asSimplifiedExpression(entity),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
-175
@@ -1,175 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain.objective
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asSimplifiedExpression
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.BiggerBrain
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.LookingTracker
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.RegularMovementTracker
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.Distraction
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.DistractionType
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.EntityFixation
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.LookAndMoveFixation
|
||||
import com.cobblemon.mod.common.api.ai.config.objective.ObjectiveConfig
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.mainThreadRuntime
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.entity.ai.util.LandRandomPos
|
||||
import net.minecraft.world.entity.player.Player
|
||||
|
||||
class AvoidTarget(
|
||||
private val speedMultiplier: Expression = "0.5".asExpression(),
|
||||
) : Objective {
|
||||
private var movementTask: EntityFixation? = null
|
||||
private var remainingCooldownTicks = 0
|
||||
|
||||
override val observedMemories = listOf(MemoryModuleType.AVOID_TARGET)
|
||||
|
||||
override fun getDescription(entity: LivingEntity) = "Avoiding target"
|
||||
|
||||
override fun perform(
|
||||
entity: LivingEntity,
|
||||
brain: BiggerBrain,
|
||||
activeObjectiveTags: MutableSet<String>
|
||||
): ObjectiveStatus {
|
||||
if (entity !is PokemonEntity || !entity.isAlive) return ObjectiveStatus.INVALID
|
||||
|
||||
val target = brain.getMemory(MemoryModuleType.AVOID_TARGET)
|
||||
?: return ObjectiveStatus.INACTIVE
|
||||
|
||||
if (target.isRemoved || target.isDeadOrDying) {
|
||||
brain.eraseMemory(MemoryModuleType.AVOID_TARGET)
|
||||
return ObjectiveStatus.INACTIVE
|
||||
}
|
||||
|
||||
if (target is Player && (target.isCreative || target.isSpectator)) {
|
||||
brain.eraseMemory(MemoryModuleType.AVOID_TARGET)
|
||||
return ObjectiveStatus.INACTIVE
|
||||
}
|
||||
|
||||
if (brain.isFixation(movementTask)) {
|
||||
return ObjectiveStatus.FIXATED
|
||||
}
|
||||
|
||||
if (remainingCooldownTicks > 0) {
|
||||
remainingCooldownTicks--
|
||||
}
|
||||
|
||||
val runtime = mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
val speed = runtime.resolveFloat(speedMultiplier)
|
||||
|
||||
|
||||
// If we have a current target, check if it's still valid and within roam range (if tethered)
|
||||
if (target.isAlive) {
|
||||
val tethering = (entity).tethering
|
||||
if (tethering != null && !tethering.canRoamTo(target.blockPosition())) {
|
||||
// Target moved out of range let's kill the memory >:)
|
||||
brain.distract(Distraction.FORCE)
|
||||
entity.brain.eraseMemory(MemoryModuleType.AVOID_TARGET)
|
||||
}
|
||||
}
|
||||
|
||||
if (brain.isFixation(movementTask)) {
|
||||
return ObjectiveStatus.FIXATED
|
||||
}
|
||||
|
||||
if (!brain.distract(Distraction.FORCE)) return ObjectiveStatus.BLOCKED
|
||||
var targetPos : BlockPos? = null
|
||||
|
||||
// TODO: utilize wander target rules to find a valid target position
|
||||
val direction = entity.position().subtract(target.position())
|
||||
for (j in 0..9) {
|
||||
val targetVec3 = LandRandomPos.getPosAway(entity, 16, 7, direction)
|
||||
if (targetVec3 != null) {
|
||||
targetPos = BlockPos.containing(targetVec3)
|
||||
break
|
||||
}
|
||||
}
|
||||
// val walkTarget = WanderAround.generateWalkTarget(entity)
|
||||
if (targetPos != null) {
|
||||
val movementTracker = RegularMovementTracker.attempt(
|
||||
entity = entity,
|
||||
walkTarget = WalkTarget(
|
||||
targetPos,
|
||||
speed,
|
||||
0
|
||||
)
|
||||
)
|
||||
if (movementTracker != null) {
|
||||
movementTask = brain.fixate(
|
||||
LookAndMoveFixation(
|
||||
distractionTypes = setOf(
|
||||
DistractionType.FORCE
|
||||
),
|
||||
lookingTracker = LookingTracker.fromNavigationPathOrWalkTarget(
|
||||
entity,
|
||||
movementTracker.walkTarget
|
||||
),
|
||||
movementTracker = movementTracker,
|
||||
description = "Moving away from target entity",
|
||||
)
|
||||
)
|
||||
return ObjectiveStatus.FIXATED
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return ObjectiveStatus.ACTIVE
|
||||
}
|
||||
|
||||
override fun onRegister(entity: LivingEntity, brain: BiggerBrain) {
|
||||
brain.subscribe(
|
||||
priority = Priority.LOW,
|
||||
memory = MemoryModuleType.AVOID_TARGET
|
||||
) { value, labels ->
|
||||
if (value == null) {
|
||||
if (brain.isFixation(movementTask)) {
|
||||
brain.distract(Distraction.FORCE)
|
||||
movementTask = null
|
||||
}
|
||||
}
|
||||
return@subscribe true
|
||||
}
|
||||
}
|
||||
|
||||
class Config : ObjectiveConfig {
|
||||
val speedMultiplier: ExpressionOrEntityVariable = Either.left("0.5".asExpression())
|
||||
|
||||
override fun getVariables(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): List<MoLangConfigVariable> {
|
||||
return listOf(speedMultiplier).asVariables()
|
||||
}
|
||||
|
||||
override fun create(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): Objective {
|
||||
return AvoidTarget(
|
||||
speedMultiplier = speedMultiplier.asSimplifiedExpression(entity),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
-306
@@ -1,306 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain.objective
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asSimplifiedExpression
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.BiggerBrain
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.LookingTracker
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.RegularMovementTracker
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.Distraction
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.DistractionType
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.comfortDistraction
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.DurationLockFixation
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.EntityFixation
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.LookAndMoveFixation
|
||||
import com.cobblemon.mod.common.api.ai.config.objective.ObjectiveConfig
|
||||
import com.cobblemon.mod.common.api.ai.resolveInt as resolveVariableInt
|
||||
import com.cobblemon.mod.common.api.breeding.CobblemonBreeding
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.nest.WildNestType
|
||||
import com.cobblemon.mod.common.api.nest.WildNestTypes
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.block.WildNestBlock
|
||||
import com.cobblemon.mod.common.block.entity.NestBlockEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.mainThreadRuntime
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.particles.ParticleTypes
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class Breed(
|
||||
private val speedMultiplier: Expression = "0.4".asExpression(),
|
||||
private val condition: Expression = "true".asExpression(),
|
||||
private val layDurationTicks: Int = 40
|
||||
) : Objective {
|
||||
private var fixation: EntityFixation? = null
|
||||
private var mateFixation: EntityFixation? = null
|
||||
|
||||
override fun getDescription(entity: LivingEntity) = "Breed"
|
||||
|
||||
override fun perform(entity: LivingEntity, brain: BiggerBrain, activeObjectiveTags: MutableSet<String>): ObjectiveStatus {
|
||||
if (entity !is PokemonEntity || !entity.isAlive)
|
||||
return ObjectiveStatus.INVALID
|
||||
val world = entity.level() as? ServerLevel ?: return ObjectiveStatus.INVALID
|
||||
val mate = brain.getMemory(CobblemonMemories.POTENTIAL_MATE) as? PokemonEntity ?: return ObjectiveStatus.INACTIVE
|
||||
if (!mate.isAlive || mate.level() != world)
|
||||
return ObjectiveStatus.INACTIVE
|
||||
// ignore wild pokemon who are already parents of a nest
|
||||
if (entity.pokemon.isWild() && brain.hasMemoryValue(CobblemonMemories.PATERNAL_NEST_LOCATION))
|
||||
return ObjectiveStatus.INACTIVE
|
||||
// make sure either parent doesn't have an active breeding cooldown (do we want to only do this for the females?)
|
||||
if (entity.pokemon.breedingCooldown != 0 || mate.pokemon.breedingCooldown != 0)
|
||||
return ObjectiveStatus.INACTIVE
|
||||
// is breeding disabled from any preset conditions
|
||||
if (!mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue()).resolveBoolean(condition))
|
||||
return ObjectiveStatus.INACTIVE
|
||||
// try to get one parent to lead the other one and have the other one not do this stuff
|
||||
if (entity.uuid > mate.uuid)
|
||||
return ObjectiveStatus.INACTIVE
|
||||
|
||||
val nestPos = brain.getMemory(CobblemonMemories.NEST_LOCATION)
|
||||
if (nestPos != null)
|
||||
return breedAtNest(entity, brain, mate, world, nestPos)
|
||||
val idealNestPos = brain.getMemory(CobblemonMemories.IDEAL_NEST_LOCATION) ?: return ObjectiveStatus.INACTIVE
|
||||
return buildNest(entity, brain, mate, world, idealNestPos)
|
||||
}
|
||||
|
||||
// get both parents to go to the nest and breed once within range
|
||||
private fun breedAtNest(entity: PokemonEntity, brain: BiggerBrain, mate: PokemonEntity, world: ServerLevel, nestPos: BlockPos): ObjectiveStatus {
|
||||
val nest = world.getBlockEntity(nestPos) as? NestBlockEntity ?: return ObjectiveStatus.INACTIVE
|
||||
if (!canUseNest(entity, mate, world, nest))
|
||||
return ObjectiveStatus.INACTIVE
|
||||
if (!nest.getItem().isEmpty)
|
||||
return ObjectiveStatus.INACTIVE
|
||||
// make sure these lovers claim the nest because others may try to at the same time
|
||||
nest.nestClaimedBy = Pair(entity.uuid, mate.uuid)
|
||||
|
||||
val nestCenter = Vec3.atCenterOf(nestPos)
|
||||
val speed = mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue()).resolveFloat(speedMultiplier)
|
||||
// path to the nest site with mate until close enough (big bois had issues so we are also going to try to make it easier for them)
|
||||
if (entity.position().distanceTo(nestCenter) > closeEnough(entity) || mate.position().distanceTo(nestCenter) > closeEnough(mate)) {
|
||||
bringMate(mate, nestCenter, speed)
|
||||
return walkToNest(entity, brain, nestCenter, speed, "in Breed fixation: going to nest")
|
||||
}
|
||||
return layEgg(entity, brain, mate, world, nest, nestPos)
|
||||
}
|
||||
|
||||
// have both mates go to a ideal spot to make a nest
|
||||
private fun buildNest(entity: PokemonEntity, brain: BiggerBrain, mate: PokemonEntity, world: ServerLevel, nestPos: BlockPos): ObjectiveStatus {
|
||||
// probably should stop trying to build nest if there is an attack target
|
||||
if (brain.hasMemoryValue(MemoryModuleType.ATTACK_TARGET))
|
||||
return ObjectiveStatus.INACTIVE
|
||||
// find out what kinds of nests this couple can make togethr
|
||||
val types = WildNestTypes.combinedTypes(entity, mate)
|
||||
if (types.isEmpty())
|
||||
return ObjectiveStatus.INACTIVE
|
||||
|
||||
val nestCenter = Vec3.atCenterOf(nestPos)
|
||||
val speed = mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue()).resolveFloat(speedMultiplier)
|
||||
// keep going until both mates are not too far from the nest
|
||||
if (entity.position().distanceTo(nestCenter) > closeEnough(entity) || mate.position().distanceTo(nestCenter) > closeEnough(mate)) {
|
||||
bringMate(mate, nestCenter, speed)
|
||||
return walkToNest(entity, brain, nestCenter, speed, "in Breed fixation: going to nest")
|
||||
}
|
||||
|
||||
// get our nest they are about to build and place it
|
||||
val nestToBuild = WildNestTypes.resolvePlacement(types, world.getBlockState(nestPos.below()), world.getFluidState(nestPos)) ?: return ObjectiveStatus.INACTIVE
|
||||
val nestBlock = WildNestTypes.blockFor(nestToBuild.type) as? WildNestBlock ?: return ObjectiveStatus.INACTIVE
|
||||
var nestState = nestBlock.defaultBlockState().setValue(BlockStateProperties.WATERLOGGED, nestToBuild.waterlogged)
|
||||
nestBlock.variantProperty?.let { nestState = nestState.setValue(it, nestToBuild.variant) }
|
||||
world.setBlock(nestPos, nestState, 3)
|
||||
|
||||
// set the parents of the nest (hope this isn't too early to do this, might need to be after egg laying instead..)
|
||||
(world.getBlockEntity(nestPos) as? NestBlockEntity)?.nestClaimedBy = Pair(entity.uuid, mate.uuid)
|
||||
|
||||
for (parentBrain in listOf(brain, mate.biggerBrain)) {
|
||||
parentBrain.eraseMemory(CobblemonMemories.IDEAL_NEST_LOCATION)
|
||||
// give our newly made nest to the parents now taht it exists
|
||||
parentBrain.setMemory(CobblemonMemories.NEST_LOCATION, nestPos)
|
||||
}
|
||||
return ObjectiveStatus.ACTIVE
|
||||
}
|
||||
|
||||
// make da baby and tell the parents about their new responsibility in life
|
||||
private fun layEgg(entity: PokemonEntity, brain: BiggerBrain, mate: PokemonEntity, world: ServerLevel, nest: NestBlockEntity, nestPos: BlockPos): ObjectiveStatus {
|
||||
if (!brain.distract(Distraction.FORCE))
|
||||
return ObjectiveStatus.BLOCKED
|
||||
val egg = CobblemonBreeding.createEgg(entity.pokemon, mate.pokemon) ?: return ObjectiveStatus.INACTIVE
|
||||
nest.setItem(egg)
|
||||
|
||||
// wild nests are probably the only ones where we need to record the parents onto the nest
|
||||
if (nest.ownerUUID == null) {
|
||||
nest.parents = Pair(entity.uuid, mate.uuid)
|
||||
nest.nestClaimedBy = Pair(entity.uuid, mate.uuid)
|
||||
}
|
||||
|
||||
for (parent in listOf(entity, mate)) {
|
||||
// might want to do the destiny knot damaging here for each parent that has one
|
||||
if (Cobblemon.config.canDestinyKnotBreak)
|
||||
if (parent.pokemon.heldItem.item == CobblemonItems.DESTINY_KNOT.asItem()) {
|
||||
parent.pokemon.heldItemNoCopy().damageValue += 1
|
||||
}
|
||||
|
||||
parent.pokemon.breedingCooldown = CobblemonBreeding.resetBreedingCooldown(parent.pokemon)
|
||||
parent.biggerBrain.setMemory(CobblemonMemories.PATERNAL_NEST_LOCATION, nestPos)
|
||||
parent.biggerBrain.setMemory(CobblemonMemories.EGG_IN_NEST, true)
|
||||
parent.biggerBrain.eraseMemory(CobblemonMemories.IDEAL_NEST_LOCATION)
|
||||
|
||||
// todo do we want to use our own particles? look at this later
|
||||
world.sendParticles(
|
||||
ParticleTypes.HEART,
|
||||
parent.getRandomX(1.0),
|
||||
parent.getRandomY() + 0.5,
|
||||
parent.getRandomZ(1.0),
|
||||
4 + parent.random.nextInt(2),
|
||||
0.2 * parent.random.nextGaussian(),
|
||||
0.1 * parent.random.nextGaussian(),
|
||||
0.2 * parent.random.nextGaussian(),
|
||||
0.02
|
||||
)
|
||||
}
|
||||
// try to keep them in one spot for a bit to give time for the magic to happen
|
||||
fixation = brain.fixate(DurationLockFixation("Breed: laying egg", layDurationTicks))
|
||||
if (mate.biggerBrain.distract(Distraction.FORCE)) {
|
||||
mateFixation = mate.biggerBrain.fixate(DurationLockFixation("Breed: laying egg as the mate", layDurationTicks))
|
||||
}
|
||||
return ObjectiveStatus.FIXATED
|
||||
}
|
||||
|
||||
// path to the nest location
|
||||
private fun walkToNest(entity: PokemonEntity, brain: BiggerBrain, target: Vec3, speed: Float, description: String): ObjectiveStatus {
|
||||
if (brain.isFixation(fixation))
|
||||
return ObjectiveStatus.FIXATED
|
||||
// wait for mate to get here
|
||||
if (entity.position().distanceTo(target) <= closeEnough(entity))
|
||||
return ObjectiveStatus.ACTIVE
|
||||
if (!brain.distract(comfortDistraction))
|
||||
return ObjectiveStatus.BLOCKED
|
||||
val tracker = RegularMovementTracker.attempt(entity, WalkTarget(target, speed, closeEnough(entity).toInt())) ?: return ObjectiveStatus.ACTIVE
|
||||
fixation = brain.fixate(
|
||||
LookAndMoveFixation(
|
||||
distractionTypes = setOf(DistractionType.DAMAGE, DistractionType.FORCE),
|
||||
description = description,
|
||||
lookingTracker = LookingTracker.fromNavigationPathOrWalkTarget(entity, tracker.walkTarget),
|
||||
movementTracker = tracker
|
||||
)
|
||||
)
|
||||
return ObjectiveStatus.FIXATED
|
||||
}
|
||||
|
||||
// have the other mates be told where to go
|
||||
private fun bringMate(mate: PokemonEntity, target: Vec3, speed: Float) {
|
||||
val mateBrain = mate.biggerBrain
|
||||
if (mate.position().distanceTo(target) <= closeEnough(mate) || mateBrain.isFixation(mateFixation))
|
||||
return
|
||||
if (!mateBrain.distract(comfortDistraction))
|
||||
return
|
||||
val tracker = RegularMovementTracker.attempt(mate, WalkTarget(target, speed, closeEnough(mate).toInt())) ?: return
|
||||
mateFixation = mateBrain.fixate(
|
||||
LookAndMoveFixation(
|
||||
distractionTypes = setOf(DistractionType.DAMAGE, DistractionType.FORCE),
|
||||
description = "Breed: folow mate",
|
||||
lookingTracker = LookingTracker.fromNavigationPathOrWalkTarget(mate, tracker.walkTarget),
|
||||
movementTracker = tracker
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// checks for what nests are valid for the mates
|
||||
private fun canUseNest(entity: PokemonEntity, mate: PokemonEntity, world: ServerLevel, nest: NestBlockEntity): Boolean {
|
||||
val nestType = (nest.blockState.block as? WildNestBlock)?.type ?: return false
|
||||
if (!isNestTypeAllowed(nestType, entity, mate))
|
||||
return false
|
||||
val waterlogged = nest.blockState.getOptionalValue(BlockStateProperties.WATERLOGGED).orElse(false)
|
||||
if (!isWaterGroupCompatible(entity, mate, waterlogged))
|
||||
return false
|
||||
|
||||
// check if the nest is claimed by other pokemon that exist and maybe on their way to it (CRAB NOTE: This helps prevent swarms of mons going to the same nest which looked weird)
|
||||
val (existingParent1, existingParent2) = nest.nestClaimedBy
|
||||
val claimedByMate1 = existingParent1 != null && existingParent1 != entity.uuid && world.getEntity(existingParent1) != null
|
||||
val claimedByMate2 = existingParent2 != null && existingParent2 != entity.uuid && world.getEntity(existingParent2) != null
|
||||
if (claimedByMate1 && claimedByMate2)
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
// make sure the nest type works for the mates and that wild use wild nests and owned pokemon use player placed nests
|
||||
private fun isNestTypeAllowed(nestType: WildNestType, entity: PokemonEntity, mate: PokemonEntity): Boolean {
|
||||
val allowed = WildNestTypes.combinedTypes(entity, mate).toMutableSet()
|
||||
if (!entity.pokemon.isWild() && !mate.pokemon.isWild()) {
|
||||
allowed.add(WildNestType.PLAYER)
|
||||
allowed.add(WildNestType.KELP)
|
||||
}
|
||||
if (nestType == WildNestType.PLAYER || nestType == WildNestType.KELP)
|
||||
return !entity.pokemon.isWild() && nestType in allowed
|
||||
return nestType in allowed
|
||||
}
|
||||
|
||||
// waterlogged nests only allow parents that both have a water egg group and land nests dont work for mates that only have water egg groups
|
||||
private fun isWaterGroupCompatible(entity: PokemonEntity, mate: PokemonEntity, nestWaterlogged: Boolean): Boolean {
|
||||
val mate1Groups = entity.pokemon.species.eggGroups.map { it.name.lowercase() }
|
||||
val mate2Groups = mate.pokemon.species.eggGroups.map { it.name.lowercase() }
|
||||
val mate1HasWaterGroup = mate1Groups.any { it in WATER_EGG_GROUPS || it == "ditto" }
|
||||
val mate2HasWaterGroup = mate2Groups.any { it in WATER_EGG_GROUPS || it == "ditto" }
|
||||
val mate1OnlyWaterGroup = mate1Groups.all { it in WATER_EGG_GROUPS }
|
||||
val mate2OnlyWaterGroup = mate2Groups.all { it in WATER_EGG_GROUPS }
|
||||
|
||||
return if (nestWaterlogged) mate1HasWaterGroup && mate2HasWaterGroup else !(mate1OnlyWaterGroup || mate2OnlyWaterGroup)
|
||||
}
|
||||
|
||||
class Config : ObjectiveConfig {
|
||||
val speedMultiplier: ExpressionOrEntityVariable = Either.left("0.4".asExpression())
|
||||
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
val layDurationTicks: ExpressionOrEntityVariable = Either.left("40".asExpression())
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): List<MoLangConfigVariable> {
|
||||
return listOf(speedMultiplier, condition, layDurationTicks).asVariables()
|
||||
}
|
||||
|
||||
override fun create(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): Objective {
|
||||
behaviourConfigurationContext.addMemories(
|
||||
CobblemonMemories.POTENTIAL_MATE,
|
||||
CobblemonMemories.NEST_LOCATION,
|
||||
CobblemonMemories.PATERNAL_NEST_LOCATION,
|
||||
CobblemonMemories.IDEAL_NEST_LOCATION,
|
||||
CobblemonMemories.EGG_IN_NEST,
|
||||
MemoryModuleType.ATTACK_TARGET
|
||||
)
|
||||
return Breed(
|
||||
speedMultiplier = speedMultiplier.asSimplifiedExpression(entity),
|
||||
condition = condition.asSimplifiedExpression(entity),
|
||||
layDurationTicks = layDurationTicks.resolveVariableInt(behaviourConfigurationContext.runtime)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// lets help those with more cushion for the pushing reach those nests to breed
|
||||
private fun closeEnough(entity: PokemonEntity) = CLOSE_ENOUGH_DISTANCE + entity.bbWidth / 2
|
||||
|
||||
companion object {
|
||||
private const val CLOSE_ENOUGH_DISTANCE = 1.5 // we will have this be our baseline and then scale based on hitbox (like above) for the bigger mons
|
||||
private val WATER_EGG_GROUPS = setOf("water_1", "water_2", "water_3")
|
||||
}
|
||||
}
|
||||
-167
@@ -1,167 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain.objective
|
||||
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.BiggerBrain
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.MovementTracker
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.Distraction
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.idleBoredomDistraction
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.EntityFixation
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.MovementTrackerFixation
|
||||
import com.cobblemon.mod.common.api.ai.config.objective.ObjectiveConfig
|
||||
import com.cobblemon.mod.common.api.ai.resolveFloat
|
||||
import com.cobblemon.mod.common.api.ai.resolveInt
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.PokemonMoveControl
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
|
||||
/**
|
||||
* Swim or fly in a circle objective
|
||||
*/
|
||||
class CircleAround(
|
||||
val poseTypes: Set<PoseType>,
|
||||
val minTurnAngleDegrees: Float,
|
||||
val maxTurnAngleDegrees: Float,
|
||||
val verticalSpeed: Float,
|
||||
val speed: Float,
|
||||
val minDurationTicks: Int = 60,
|
||||
val maxDurationTicks: Int = 180
|
||||
) : Objective {
|
||||
var chosenTurnAngle = 0F
|
||||
var chosenDuration = 0
|
||||
var fixation: EntityFixation? = null
|
||||
var moveControl: PokemonMoveControl? = null
|
||||
|
||||
override fun getDescription(entity: LivingEntity) = "Circling"
|
||||
override fun perform(
|
||||
entity: LivingEntity,
|
||||
brain: BiggerBrain,
|
||||
activeObjectiveTags: MutableSet<String>
|
||||
): ObjectiveStatus {
|
||||
if (entity !is PokemonEntity) {
|
||||
return ObjectiveStatus.INVALID
|
||||
} else if (brain.isFixation(fixation)) {
|
||||
return ObjectiveStatus.FIXATED
|
||||
} else if (entity.getCurrentPoseType() !in poseTypes) {
|
||||
return ObjectiveStatus.BLOCKED
|
||||
} else if (brain.fixation != null) {
|
||||
fixation = null
|
||||
return ObjectiveStatus.BLOCKED // Since this doesn't distract anything then if the brain is fixated at all we are blocked
|
||||
}
|
||||
|
||||
// TODO: should this not be able to distract anything? relates to the above fixation comment
|
||||
// if (!brain.distract(idleBoredomDistraction)) {
|
||||
// return ObjectiveStatus.BLOCKED
|
||||
// }
|
||||
|
||||
entity.brain.eraseMemory(MemoryModuleType.WALK_TARGET)
|
||||
entity.navigation.stop()
|
||||
|
||||
// Gather a random turn angle and random duration
|
||||
this.chosenTurnAngle = entity.random.nextFloat() * (maxTurnAngleDegrees - minTurnAngleDegrees) + minTurnAngleDegrees
|
||||
if (entity.random.nextBoolean()) {
|
||||
chosenTurnAngle = -chosenTurnAngle
|
||||
}
|
||||
chosenDuration = entity.random.nextIntBetweenInclusive(minDurationTicks, maxDurationTicks)
|
||||
|
||||
// Grab moveControl off the entity to use during fixation
|
||||
this.moveControl = entity.moveControl as PokemonMoveControl?
|
||||
|
||||
|
||||
// Become fixated
|
||||
fixation = brain.fixate(
|
||||
CircleAroundFixation(
|
||||
this,
|
||||
null,
|
||||
chosenDuration
|
||||
)
|
||||
)
|
||||
return ObjectiveStatus.ACTIVE //TODO: should this have a cooldown? Currently just having it as the pure fallback and able to be distracted by anything. I guess fishes should always swim... probably not but I'll sort that later
|
||||
}
|
||||
|
||||
|
||||
class CircleAroundFixation(
|
||||
val objective: CircleAround,
|
||||
override val movementTracker: MovementTracker?,
|
||||
var timer: Int
|
||||
) : EntityFixation, MovementTrackerFixation {
|
||||
override fun getDescription(entity: LivingEntity) = "Circling around at ${this.objective.chosenTurnAngle} degrees for ${this.timer} more ticks"
|
||||
override fun onDistract(distraction: Distraction, entity: LivingEntity) {
|
||||
super.onDistract(distraction, entity)
|
||||
objective.moveControl?.stopBanking()
|
||||
}
|
||||
|
||||
// can be distracted by anything
|
||||
override fun canDistract(distraction: Distraction, entity: LivingEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun tick(entity: LivingEntity, brain: BiggerBrain): Boolean {
|
||||
objective.moveControl?.startBanking(
|
||||
forwardBlocksPerTick = objective.speed,
|
||||
upwardsBlocksPerTick = objective.verticalSpeed,
|
||||
rightDegreesPerTick = objective.chosenTurnAngle,
|
||||
durationTicks = 2 //TODO: is it odd we have the check in multiple spots?
|
||||
)
|
||||
this.timer--
|
||||
if (this.timer < 0 || (entity as PokemonEntity).getCurrentPoseType() !in objective.poseTypes) {
|
||||
objective.moveControl?.stopBanking()
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
class Config : ObjectiveConfig {
|
||||
val poseTypes: Set<PoseType> = setOf(PoseType.FLY, PoseType.HOVER)
|
||||
val minAngularVelocityDegrees: ExpressionOrEntityVariable = Either.left("0.0".asExpression())
|
||||
val maxAngularVelocityDegrees: ExpressionOrEntityVariable = Either.left("1.0".asExpression())
|
||||
val speed: ExpressionOrEntityVariable = Either.left("0.6".asExpression())
|
||||
val verticalSpeed: ExpressionOrEntityVariable = Either.left("0.0".asExpression())
|
||||
val minDurationTicks: ExpressionOrEntityVariable = Either.left("60".asExpression())
|
||||
val maxDurationTicks: ExpressionOrEntityVariable = Either.left("180".asExpression())
|
||||
|
||||
|
||||
override fun getVariables(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
) = listOf(
|
||||
minAngularVelocityDegrees,
|
||||
maxAngularVelocityDegrees,
|
||||
speed,
|
||||
verticalSpeed,
|
||||
minDurationTicks,
|
||||
maxDurationTicks
|
||||
).asVariables()
|
||||
|
||||
override fun create(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): Objective? {
|
||||
if (entity !is PokemonEntity) return null
|
||||
return CircleAround(
|
||||
poseTypes = poseTypes,
|
||||
minTurnAngleDegrees = minAngularVelocityDegrees.resolveFloat(behaviourConfigurationContext.runtime),
|
||||
maxTurnAngleDegrees = maxAngularVelocityDegrees.resolveFloat(behaviourConfigurationContext.runtime),
|
||||
speed = speed.resolveFloat(behaviourConfigurationContext.runtime),
|
||||
verticalSpeed = verticalSpeed.resolveFloat(behaviourConfigurationContext.runtime),
|
||||
minDurationTicks = minDurationTicks.resolveInt(behaviourConfigurationContext.runtime),
|
||||
maxDurationTicks = maxDurationTicks.resolveInt(behaviourConfigurationContext.runtime)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
-158
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain.objective
|
||||
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.BiggerBrain
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.MovementStatus
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.MovementTracker
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.Distraction
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.idleBoredomDistraction
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.EntityFixation
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.MovementTrackerFixation
|
||||
import com.cobblemon.mod.common.api.ai.config.objective.ObjectiveConfig
|
||||
import com.cobblemon.mod.common.api.ai.resolveFloat
|
||||
import com.cobblemon.mod.common.api.ai.resolveInt
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonBehaviourFlag
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
|
||||
/**
|
||||
* Stops movement and plays a Pokemon's dance animation, if available.
|
||||
*
|
||||
*/
|
||||
class Dance(
|
||||
val minDuration: Int,
|
||||
val danceChance: Float
|
||||
) : Objective {
|
||||
var fixation: EntityFixation? = null
|
||||
var remainingCooldownTicks = 0
|
||||
override fun getDescription(entity: LivingEntity) = "Dancing"
|
||||
override fun perform(
|
||||
entity: LivingEntity,
|
||||
brain: BiggerBrain,
|
||||
activeObjectiveTags: MutableSet<String>
|
||||
): ObjectiveStatus {
|
||||
if (entity !is PokemonEntity) {
|
||||
return ObjectiveStatus.INVALID
|
||||
} else if (brain.isFixation(fixation)) {
|
||||
remainingCooldownTicks = ticksBetweenAttempts
|
||||
return ObjectiveStatus.FIXATED
|
||||
} else if (brain.fixation != null) {
|
||||
fixation = null
|
||||
}
|
||||
|
||||
if (remainingCooldownTicks > 0) {
|
||||
remainingCooldownTicks--
|
||||
return ObjectiveStatus.INACTIVE
|
||||
}
|
||||
|
||||
// Only dance if we feel like it
|
||||
val danceMemory = brain.getMemory(MemoryModuleType.DANCING) ?: false
|
||||
if (!danceMemory || entity.random.nextFloat() > danceChance || entity.ticksLived < 4 * 20) {
|
||||
return ObjectiveStatus.INACTIVE
|
||||
}
|
||||
|
||||
if (!brain.distract(idleBoredomDistraction)) {
|
||||
return ObjectiveStatus.BLOCKED
|
||||
}
|
||||
|
||||
entity.brain.eraseMemory(MemoryModuleType.WALK_TARGET)
|
||||
entity.navigation.stop()
|
||||
|
||||
|
||||
// Become fixated
|
||||
fixation = brain.fixate(
|
||||
DanceFixation(
|
||||
this,
|
||||
null,
|
||||
minDuration
|
||||
)
|
||||
)
|
||||
return ObjectiveStatus.ACTIVE
|
||||
}
|
||||
|
||||
|
||||
class DanceFixation(
|
||||
val objective: Dance,
|
||||
override val movementTracker: MovementTracker?,
|
||||
val minDuration: Int
|
||||
) : EntityFixation, MovementTrackerFixation {
|
||||
var ticksSinceStarted = 0
|
||||
override fun getDescription(entity: LivingEntity) = "Dancing"
|
||||
override fun tickMovementFixation() = MovementStatus.PENDING
|
||||
|
||||
override fun onDistract(distraction: Distraction, entity: LivingEntity) {
|
||||
super.onDistract(distraction, entity)
|
||||
stopDancing(entity)
|
||||
}
|
||||
|
||||
override fun canDistract(distraction: Distraction, entity: LivingEntity): Boolean {
|
||||
if (distraction.isIdleBoredom) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun stopDancing(entity: LivingEntity) {
|
||||
val pokemon = entity as? PokemonEntity ?: return
|
||||
pokemon.setBehaviourFlag(PokemonBehaviourFlag.DANCING, false)
|
||||
}
|
||||
|
||||
override fun tick(entity: LivingEntity, brain: BiggerBrain): Boolean {
|
||||
if (ticksSinceStarted == 0) { // Makes make me want a Start() for fixations
|
||||
val pokemon = entity as? PokemonEntity ?: return false
|
||||
RunPosableMoLangPacket(entity.id, setOf("v.bpm = 100;")).sendToPlayersAround(entity, 64.0)
|
||||
pokemon.setBehaviourFlag(PokemonBehaviourFlag.DANCING, true)
|
||||
}
|
||||
ticksSinceStarted++
|
||||
if (ticksSinceStarted > minDuration && !entity.brain.getMemorySafely(MemoryModuleType.DANCING).orElse(false)) {
|
||||
stopDancing(entity)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
class Config : ObjectiveConfig {
|
||||
var danceChance: ExpressionOrEntityVariable = Either.left("1/2".asExpression())
|
||||
var minDuration: ExpressionOrEntityVariable = Either.left("60".asExpression())
|
||||
|
||||
override fun getVariables(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
) = listOf(
|
||||
minDuration,
|
||||
danceChance
|
||||
).asVariables()
|
||||
|
||||
override fun create(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): Objective {
|
||||
val minDuration = minDuration.resolveInt(behaviourConfigurationContext.runtime)
|
||||
val danceChance = danceChance.resolveFloat(behaviourConfigurationContext.runtime)
|
||||
return Dance(
|
||||
minDuration,
|
||||
danceChance)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ticksBetweenAttempts = 20
|
||||
}
|
||||
}
|
||||
-384
@@ -1,384 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain.objective
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asSimplifiedExpression
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.BiggerBrain
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.LookingTracker
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.RegularMovementTracker
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.Distraction
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.DistractionType
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.comfortDistraction
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.AttackFixation
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.EntityFixation
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.LookAndLockFixation
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.LookAndMoveFixation
|
||||
import com.cobblemon.mod.common.api.ai.config.objective.ObjectiveConfig
|
||||
import com.cobblemon.mod.common.api.ai.resolveInt as resolveVariableInt
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.isInBattle
|
||||
import com.cobblemon.mod.common.util.mainThreadRuntime
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.particles.ParticleTypes
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class DefendNest(
|
||||
speedMultiplier: Expression = "0.5".asExpression(),
|
||||
warnRange: Expression = "15.0".asExpression(),
|
||||
private val attackRange: Expression = "8.0".asExpression(),
|
||||
disengageRange: Expression = "20.0".asExpression(),
|
||||
condition: Expression = "true".asExpression(),
|
||||
targetCondition: Expression = "true".asExpression(),
|
||||
description: Expression = "'Defend Nest'".asExpression(),
|
||||
private val maxAttackDuration: Expression = "300".asExpression(),
|
||||
private val patrolMinRadius: Int = 4,
|
||||
private val patrolMaxRadius: Int = 8
|
||||
) : EntityResponseObjective(
|
||||
speedMultiplier = speedMultiplier,
|
||||
engageRange = warnRange,
|
||||
disengageRange = disengageRange,
|
||||
condition = condition,
|
||||
targetCondition = targetCondition,
|
||||
description = description
|
||||
) {
|
||||
private var fixation: EntityFixation? = null
|
||||
private var scanCooldownTicks = 0
|
||||
private var cryCooldownTicks = 0
|
||||
private var patrolCooldownTicks = 0
|
||||
|
||||
override fun perform(entity: LivingEntity, brain: BiggerBrain, activeObjectiveTags: MutableSet<String>): ObjectiveStatus {
|
||||
if (entity !is PokemonEntity || !entity.isAlive)
|
||||
return ObjectiveStatus.INVALID
|
||||
// so only wild mons will guard the nest (unless we want them to later on..)
|
||||
if (!entity.pokemon.isWild())
|
||||
return ObjectiveStatus.INACTIVE
|
||||
// if the mon is battling then don't worry about defending (this was causing crying and particle spam lol)
|
||||
if (entity.isBattling)
|
||||
return ObjectiveStatus.INACTIVE
|
||||
|
||||
val nestPos = brain.getMemory(CobblemonMemories.PATERNAL_NEST_LOCATION)
|
||||
if (nestPos == null) {
|
||||
// mates used to give up attacking players if the egg and nest was gone but we should have them chase them to the ends of the earth for their crimes
|
||||
val thief = brain.getMemory(CobblemonMemories.EGG_THIEF)
|
||||
if (thief != null && thief.isAlive && entity.hasLineOfSight(thief))
|
||||
return attack(entity, brain, thief)
|
||||
return stopDefending(brain)
|
||||
}
|
||||
val eggInNest = brain.getMemory(CobblemonMemories.EGG_IN_NEST) == true
|
||||
val thief = brain.getMemory(CobblemonMemories.EGG_THIEF)
|
||||
// if we have no egg to watch over and no thief then we should not defend the nest anymore and need to switch to a different task
|
||||
if (!eggInNest && thief == null)
|
||||
return stopDefending(brain)
|
||||
|
||||
if (scanCooldownTicks > 0)
|
||||
scanCooldownTicks--
|
||||
if (cryCooldownTicks > 0)
|
||||
cryCooldownTicks--
|
||||
val nestCenter = Vec3.atCenterOf(nestPos)
|
||||
|
||||
val attackTarget = brain.getMemory(MemoryModuleType.ATTACK_TARGET)
|
||||
if (attackTarget != null && attackTarget.uuid != trackedEntity?.uuid) {
|
||||
trackedEntity = null
|
||||
return ObjectiveStatus.BLOCKED
|
||||
}
|
||||
|
||||
val tracked = trackedEntity
|
||||
if (tracked != null) {
|
||||
if (!keepTrackingPlayer(entity, brain, tracked, nestCenter)) {
|
||||
brain.eraseMemory(MemoryModuleType.ATTACK_TARGET)
|
||||
brain.eraseMemory(MemoryModuleType.ANGRY_AT)
|
||||
trackedEntity = null
|
||||
fixation = null
|
||||
return ObjectiveStatus.ACTIVE
|
||||
}
|
||||
return respondToIntruder(entity, brain, tracked, nestCenter)
|
||||
}
|
||||
|
||||
if (scanCooldownTicks <= 0) {
|
||||
scanCooldownTicks = SCAN_INTERVAL_TICKS
|
||||
trackedEntity = findIntruder(entity, brain, nestCenter)
|
||||
if (trackedEntity != null) {
|
||||
cryCooldownTicks = 0
|
||||
return ObjectiveStatus.ACTIVE
|
||||
}
|
||||
}
|
||||
return patrol(entity, brain, nestCenter, activeObjectiveTags)
|
||||
}
|
||||
|
||||
override fun onRegister(entity: LivingEntity, brain: BiggerBrain) {
|
||||
// Go after any known egg thieves
|
||||
brain.subscribe(Priority.HIGH, CobblemonMemories.EGG_THIEF) { thief, _ ->
|
||||
if (entity is PokemonEntity && thief != null) {
|
||||
if (brain.fixation !is AttackFixation) {
|
||||
trackedEntity = thief
|
||||
attack(entity, brain, thief)
|
||||
}
|
||||
} else if (thief == null && fixation is AttackFixation && brain.isFixation(fixation)) {
|
||||
brain.distract(Distraction.FORCE)
|
||||
brain.eraseMemory(MemoryModuleType.ATTACK_TARGET)
|
||||
brain.eraseMemory(MemoryModuleType.ANGRY_AT)
|
||||
trackedEntity = null
|
||||
fixation = null
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
// stop defending the nest and remove the fixation
|
||||
private fun stopDefending(brain: BiggerBrain): ObjectiveStatus {
|
||||
if (trackedEntity != null) {
|
||||
brain.eraseMemory(MemoryModuleType.ATTACK_TARGET)
|
||||
brain.eraseMemory(MemoryModuleType.ANGRY_AT)
|
||||
trackedEntity = null
|
||||
fixation = null
|
||||
}
|
||||
if (fixation is LookAndLockFixation && brain.isFixation(fixation))
|
||||
brain.distract(Distraction.FORCE)
|
||||
return ObjectiveStatus.INACTIVE
|
||||
}
|
||||
|
||||
// various checks on if a player should be tracked still
|
||||
private fun keepTrackingPlayer(entity: PokemonEntity, brain: BiggerBrain, tracked: LivingEntity, nestCenter: Vec3): Boolean {
|
||||
if (tracked.isRemoved || !tracked.isAlive)
|
||||
return false
|
||||
if (tracked is Player && (tracked.isCreative || tracked.isSpectator))
|
||||
return false
|
||||
if (tracked is ServerPlayer && tracked.isInBattle())
|
||||
return false
|
||||
if (brain.getMemory(CobblemonMemories.EGG_THIEF)?.uuid == tracked.uuid)
|
||||
return true
|
||||
val runtime = mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
return tracked.position().distanceTo(nestCenter) <= runtime.resolveFloat(disengageRange)
|
||||
}
|
||||
|
||||
// warn players that get too close or that steal an egg
|
||||
private fun respondToIntruder(entity: PokemonEntity, brain: BiggerBrain, tracked: LivingEntity, nestCenter: Vec3): ObjectiveStatus {
|
||||
val runtime = mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
val distanceToNest = tracked.position().distanceTo(nestCenter)
|
||||
val isThief = brain.getMemory(CobblemonMemories.EGG_THIEF)?.uuid == tracked.uuid
|
||||
return when {
|
||||
isThief || distanceToNest <= runtime.resolveFloat(attackRange) -> attack(entity, brain, tracked) // stop you have violated the law!
|
||||
distanceToNest <= runtime.resolveFloat(engageRange) -> warn(entity, brain, tracked, nestCenter) // almost too close!
|
||||
else -> ObjectiveStatus.ACTIVE
|
||||
}
|
||||
}
|
||||
|
||||
// force an attack fixation
|
||||
private fun attack(entity: PokemonEntity, brain: BiggerBrain, target: LivingEntity): ObjectiveStatus {
|
||||
if (fixation is AttackFixation && brain.isFixation(fixation))
|
||||
return ObjectiveStatus.FIXATED
|
||||
if (!brain.distract(Distraction.FORCE))
|
||||
return ObjectiveStatus.BLOCKED
|
||||
val runtime = mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
entity.cry()
|
||||
// todo we can use our own particles later
|
||||
(entity.level() as? ServerLevel)?.sendParticles(
|
||||
ParticleTypes.ANGRY_VILLAGER,
|
||||
entity.getRandomX(1.0),
|
||||
entity.getRandomY() + 0.5,
|
||||
entity.getRandomZ(1.0),
|
||||
4 + entity.random.nextInt(2),
|
||||
0.2 * entity.random.nextGaussian(),
|
||||
0.1 * entity.random.nextGaussian(),
|
||||
0.2 * entity.random.nextGaussian(),
|
||||
0.02
|
||||
)
|
||||
|
||||
brain.setMemory(MemoryModuleType.ATTACK_TARGET, target, runtime.resolveInt(maxAttackDuration).toLong())
|
||||
brain.setMemory(MemoryModuleType.ANGRY_AT, target.uuid)
|
||||
brain.eraseMemory(CobblemonMemories.EGG_SEARCH_COUNTDOWN)
|
||||
fixation = brain.fixate(
|
||||
AttackFixation(
|
||||
targetEntity = target,
|
||||
speedMultiplier = speedMultiplier,
|
||||
availableMoves = getRealTimeMoves(entity), // idk how this works but looks like Jazz lets us do this now
|
||||
distractionTypes = setOf(DistractionType.FORCE)
|
||||
)
|
||||
)
|
||||
return ObjectiveStatus.FIXATED
|
||||
}
|
||||
|
||||
// cry at players that get too close to the nest
|
||||
private fun warn(entity: PokemonEntity, brain: BiggerBrain, target: LivingEntity, nestCenter: Vec3): ObjectiveStatus {
|
||||
if (cryCooldownTicks <= 0) {
|
||||
entity.cry()
|
||||
// todo replace these particles later here too
|
||||
(entity.level() as? ServerLevel)?.sendParticles(
|
||||
ParticleTypes.ANGRY_VILLAGER,
|
||||
entity.getRandomX(1.0),
|
||||
entity.getRandomY() + 0.5,
|
||||
entity.getRandomZ(1.0),
|
||||
4 + entity.random.nextInt(2),
|
||||
0.2 * entity.random.nextGaussian(),
|
||||
0.1 * entity.random.nextGaussian(),
|
||||
0.2 * entity.random.nextGaussian(),
|
||||
0.02
|
||||
)
|
||||
cryCooldownTicks = CRY_COOLDOWN_TICKS + entity.random.nextInt(CRY_COOLDOWN_RANDOM_TICKS)
|
||||
}
|
||||
if (fixation is LookAndLockFixation && brain.isFixation(fixation))
|
||||
return ObjectiveStatus.FIXATED
|
||||
if (!brain.distract(Distraction.FORCE))
|
||||
return ObjectiveStatus.BLOCKED
|
||||
val runtime = mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
val warnRange = runtime.resolveFloat(engageRange)
|
||||
val attackRange = runtime.resolveFloat(attackRange)
|
||||
fixation = brain.fixate(
|
||||
LookAndLockFixation(
|
||||
lookingTracker = LookingTracker.forTargetEntity(entity, target),
|
||||
distractionTypes = setOf(DistractionType.DAMAGE, DistractionType.FORCE),
|
||||
condition = {
|
||||
val distance = target.position().distanceTo(nestCenter)
|
||||
trackedEntity?.uuid == target.uuid && distance <= warnRange && distance > attackRange
|
||||
}
|
||||
)
|
||||
)
|
||||
return ObjectiveStatus.FIXATED
|
||||
}
|
||||
|
||||
// looks for player within the warn range and too close to the nest
|
||||
private fun findIntruder(entity: PokemonEntity, brain: BiggerBrain, nestCenter: Vec3): LivingEntity? {
|
||||
val runtime = mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!runtime.resolveBoolean(condition))
|
||||
return null
|
||||
val warnRange = runtime.resolveFloat(engageRange)
|
||||
val visible = brain.getMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES) ?: return null
|
||||
|
||||
// todo how should we handle creative players?
|
||||
return visible.findAll { candidate ->
|
||||
candidate is Player &&
|
||||
!(candidate is ServerPlayer && candidate.isInBattle()) &&
|
||||
candidate.position().distanceTo(nestCenter) <= warnRange &&
|
||||
runtime.withQueryValue("target", candidate.asMostSpecificMoLangValue()).resolveBoolean(targetCondition)
|
||||
}.minByOrNull { it.position().distanceToSqr(nestCenter) }
|
||||
}
|
||||
|
||||
// pathfind around various spots around the nest
|
||||
private fun patrol(entity: PokemonEntity, brain: BiggerBrain, nestCenter: Vec3, activeObjectiveTags: MutableSet<String>): ObjectiveStatus {
|
||||
activeObjectiveTags.add(Objective.OBJECTIVE_TAG_WANDERING)
|
||||
if (fixation is LookAndMoveFixation && brain.isFixation(fixation))
|
||||
return ObjectiveStatus.FIXATED
|
||||
if (patrolCooldownTicks > 0) {
|
||||
patrolCooldownTicks--
|
||||
return ObjectiveStatus.ACTIVE
|
||||
}
|
||||
val world = entity.level() as? ServerLevel ?: return ObjectiveStatus.INVALID
|
||||
val target = findPatrolPosition(world, nestCenter, entity) ?: return ObjectiveStatus.ACTIVE
|
||||
if (!brain.distract(comfortDistraction))
|
||||
return ObjectiveStatus.BLOCKED
|
||||
val speed = mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue()).resolveFloat(speedMultiplier)
|
||||
val tracker = RegularMovementTracker.attempt(entity, WalkTarget(target, speed, 1)) ?: return ObjectiveStatus.ACTIVE
|
||||
fixation = brain.fixate(
|
||||
LookAndMoveFixation(
|
||||
distractionTypes = setOf(DistractionType.DAMAGE, DistractionType.FORCE, DistractionType.COMFORT),
|
||||
description = "patrol method in DefendNest objective",
|
||||
lookingTracker = LookingTracker.fromNavigationPathOrWalkTarget(entity, tracker.walkTarget),
|
||||
movementTracker = tracker,
|
||||
onMovementComplete = { _, _ -> patrolCooldownTicks = PATROL_PAUSE_TICKS + entity.random.nextInt(PATROL_PAUSE_RANDOM_TICKS) }
|
||||
)
|
||||
)
|
||||
return ObjectiveStatus.FIXATED
|
||||
}
|
||||
|
||||
// find pathfindable spot to patrol to
|
||||
private fun findPatrolPosition(world: ServerLevel, center: Vec3, entity: PokemonEntity): Vec3? {
|
||||
repeat(PATROL_ATTEMPTS) {
|
||||
val angle = world.random.nextDouble() * Math.PI * 2
|
||||
val radius = patrolMinRadius + world.random.nextInt(patrolMaxRadius - patrolMinRadius + 1)
|
||||
val candidate = center.add(Math.cos(angle) * radius, world.random.nextDouble() * 2 - 1, Math.sin(angle) * radius)
|
||||
val blockPos = BlockPos.containing(candidate)
|
||||
if (!world.getBlockState(blockPos).isSolidRender(world, blockPos) && entity.navigation.isStableDestination(blockPos)) {
|
||||
return Vec3.atCenterOf(blockPos)
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
class Config : ObjectiveConfig {
|
||||
val speedMultiplier: ExpressionOrEntityVariable = Either.left("0.5".asExpression())
|
||||
val warnRange: ExpressionOrEntityVariable = Either.left("15.0".asExpression())
|
||||
val attackRange: ExpressionOrEntityVariable = Either.left("8.0".asExpression())
|
||||
val disengageRange: ExpressionOrEntityVariable = Either.left("20.0".asExpression())
|
||||
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
val targetCondition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
val maxAttackDuration: ExpressionOrEntityVariable = Either.left("300".asExpression())
|
||||
val description: ExpressionOrEntityVariable = Either.left("'Defend Nest'".asExpression())
|
||||
val patrolMinRadius: ExpressionOrEntityVariable = Either.left("4".asExpression())
|
||||
val patrolMaxRadius: ExpressionOrEntityVariable = Either.left("8".asExpression())
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): List<MoLangConfigVariable> {
|
||||
return listOf(
|
||||
speedMultiplier,
|
||||
warnRange,
|
||||
attackRange,
|
||||
disengageRange,
|
||||
condition,
|
||||
targetCondition,
|
||||
maxAttackDuration,
|
||||
description,
|
||||
patrolMinRadius,
|
||||
patrolMaxRadius
|
||||
).asVariables()
|
||||
}
|
||||
|
||||
override fun create(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): Objective {
|
||||
// I don't think we need any other memory than these
|
||||
behaviourConfigurationContext.addMemories(
|
||||
CobblemonMemories.PATERNAL_NEST_LOCATION,
|
||||
CobblemonMemories.EGG_IN_NEST,
|
||||
CobblemonMemories.EGG_THIEF,
|
||||
CobblemonMemories.EGG_SEARCH_COUNTDOWN,
|
||||
MemoryModuleType.ANGRY_AT,
|
||||
MemoryModuleType.ATTACK_TARGET,
|
||||
MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES
|
||||
)
|
||||
return DefendNest(
|
||||
speedMultiplier = speedMultiplier.asSimplifiedExpression(entity),
|
||||
warnRange = warnRange.asSimplifiedExpression(entity),
|
||||
attackRange = attackRange.asSimplifiedExpression(entity),
|
||||
disengageRange = disengageRange.asSimplifiedExpression(entity),
|
||||
condition = condition.asSimplifiedExpression(entity),
|
||||
targetCondition = targetCondition.asSimplifiedExpression(entity),
|
||||
description = description.asSimplifiedExpression(entity),
|
||||
maxAttackDuration = maxAttackDuration.asSimplifiedExpression(entity),
|
||||
patrolMinRadius = patrolMinRadius.resolveVariableInt(behaviourConfigurationContext.runtime),
|
||||
patrolMaxRadius = patrolMaxRadius.resolveVariableInt(behaviourConfigurationContext.runtime)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val SCAN_INTERVAL_TICKS = 20
|
||||
private const val CRY_COOLDOWN_TICKS = 75
|
||||
private const val CRY_COOLDOWN_RANDOM_TICKS = 50
|
||||
private const val PATROL_PAUSE_TICKS = 40
|
||||
private const val PATROL_PAUSE_RANDOM_TICKS = 40
|
||||
private const val PATROL_ATTEMPTS = 20
|
||||
}
|
||||
}
|
||||
-76
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain.objective
|
||||
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.BiggerBrain
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.LookingTracker
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.MovementTracker
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.RegularMovementTracker
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.Distraction
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.DistractionType
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.comfortDistraction
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.idleBoredomDistraction
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.EntityFixation
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.LookAndMoveFixation
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.MovementTrackerFixation
|
||||
import com.cobblemon.mod.common.api.ai.config.objective.ObjectiveConfig
|
||||
import com.cobblemon.mod.common.api.ai.resolveFloat
|
||||
import com.cobblemon.mod.common.api.ai.resolveInt
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.PokemonMoveControl
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.EntityTracker
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
|
||||
/**
|
||||
* Defend owner objective
|
||||
* Handles transition of nearest visible attacker to a valid attack target when wanting to defend owner.
|
||||
* Could possibly be more configurable in the future
|
||||
*/
|
||||
class DefendOwner() : Objective {
|
||||
var cooldownTicks = 0
|
||||
|
||||
override fun getDescription(entity: LivingEntity) = "Following parent species"
|
||||
|
||||
override fun perform(
|
||||
entity: LivingEntity,
|
||||
brain: BiggerBrain,
|
||||
activeObjectiveTags: MutableSet<String>
|
||||
): ObjectiveStatus {
|
||||
if (entity !is PokemonEntity) return ObjectiveStatus.INVALID
|
||||
if (brain.hasMemoryValue(MemoryModuleType.ATTACK_TARGET)) return ObjectiveStatus.INACTIVE
|
||||
|
||||
val attacker = brain.getMemory(CobblemonMemories.NEAREST_VISIBLE_ATTACKER)
|
||||
?: return ObjectiveStatus.INACTIVE
|
||||
|
||||
brain.setMemory(MemoryModuleType.ATTACK_TARGET, attacker)
|
||||
return ObjectiveStatus.ACTIVE
|
||||
}
|
||||
|
||||
class Config : ObjectiveConfig {
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) =
|
||||
emptyList<MoLangConfigVariable>()
|
||||
|
||||
override fun create(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): Objective? {
|
||||
if (entity !is PokemonEntity) return null
|
||||
return DefendOwner()
|
||||
}
|
||||
}
|
||||
}
|
||||
-171
@@ -1,171 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain.objective
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.CobblemonAttackTargetData
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asSimplifiedExpression
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.BiggerBrain
|
||||
import com.cobblemon.mod.common.api.ai.config.objective.ObjectiveConfig
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.mainThreadRuntime
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities
|
||||
|
||||
|
||||
class Defensive(
|
||||
private val speedMultiplier: Expression = "0.5".asExpression(), // How do we transfer speed to the attack behaviour? Do we want to?
|
||||
private val engageRange: Expression = "5.0".asExpression(),
|
||||
private val disengageRange: Expression = "20.0".asExpression(),
|
||||
private val condition: Expression = "true".asExpression(),
|
||||
private val maxAttackDuration: Expression = "300".asExpression(),
|
||||
private val retaliationHitCount: Expression = "1".asExpression()
|
||||
) : Objective {
|
||||
private var remainingCooldownTicks = 0
|
||||
private var trackedEntity: LivingEntity? = null
|
||||
override val observedMemories = listOf(MemoryModuleType.HURT_BY_ENTITY, CobblemonMemories.ATTACK_TARGET_DATA)
|
||||
|
||||
override fun getDescription(entity: LivingEntity) = "Defensive Behavior"
|
||||
|
||||
override fun perform(
|
||||
entity: LivingEntity,
|
||||
brain: BiggerBrain,
|
||||
activeObjectiveTags: MutableSet<String>
|
||||
): ObjectiveStatus {
|
||||
if (entity !is PokemonEntity || !entity.isAlive) return ObjectiveStatus.INVALID
|
||||
|
||||
val attackTarget = brain.getMemory(MemoryModuleType.ATTACK_TARGET)
|
||||
val avoidTarget = brain.getMemory(MemoryModuleType.AVOID_TARGET)
|
||||
|
||||
if (trackedEntity != null) {
|
||||
if (attackTarget != null && trackedEntity?.uuid == attackTarget.uuid) {
|
||||
// Check if we continue
|
||||
return ObjectiveStatus.ACTIVE
|
||||
} else if (avoidTarget != null && trackedEntity?.uuid === avoidTarget.uuid) {
|
||||
// Check if we continue
|
||||
val runtime = mainThreadRuntime.withQueryValue("entity", (trackedEntity!!).asMostSpecificMoLangValue())
|
||||
val disengageDistance = runtime.resolveFloat(disengageRange)
|
||||
if (disengageDistance < entity.distanceTo(trackedEntity!!)) {
|
||||
brain.eraseMemory(MemoryModuleType.AVOID_TARGET)
|
||||
trackedEntity = null
|
||||
}
|
||||
} else {
|
||||
// Something has overrided us
|
||||
trackedEntity = null
|
||||
}
|
||||
} else {
|
||||
// Scan visible livingEntities
|
||||
val entities: NearestVisibleLivingEntities =
|
||||
brain.getMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES) ?: return ObjectiveStatus.INACTIVE
|
||||
|
||||
val entity = entities.findClosest { it ->
|
||||
val runtime = mainThreadRuntime.withQueryValue("entity", (it).asMostSpecificMoLangValue())
|
||||
runtime.resolveBoolean(condition) && runtime.resolveFloat(engageRange) > entity.distanceTo(it)
|
||||
}.orElse(null)
|
||||
if (entity != null) {
|
||||
trackedEntity = entity
|
||||
brain.setMemory(MemoryModuleType.AVOID_TARGET, entity)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (remainingCooldownTicks > 0) {
|
||||
remainingCooldownTicks--
|
||||
}
|
||||
|
||||
return if (trackedEntity != null) ObjectiveStatus.ACTIVE else ObjectiveStatus.INACTIVE
|
||||
}
|
||||
|
||||
override fun onRegister(entity: LivingEntity, brain: BiggerBrain) {
|
||||
brain.subscribe(
|
||||
priority = Priority.LOW,
|
||||
memory = MemoryModuleType.HURT_BY_ENTITY
|
||||
) { value, labels -> onHurtByEntityChanged(brain, value, labels) }
|
||||
|
||||
brain.subscribe(
|
||||
priority = Priority.LOW,
|
||||
memory = CobblemonMemories.ATTACK_TARGET_DATA
|
||||
) { value, labels -> onAttackTargetDataChanged(brain, value, labels) }
|
||||
}
|
||||
|
||||
fun onHurtByEntityChanged(brain: BiggerBrain, livingEntity: LivingEntity?, labels: MutableSet<String>): Boolean {
|
||||
if (livingEntity != null) {
|
||||
// Something just smacked us, see if we should get mad about it.
|
||||
val livingEntity = livingEntity as LivingEntity
|
||||
val runtime = mainThreadRuntime.withQueryValue("entity", (livingEntity).asMostSpecificMoLangValue())
|
||||
val shouldTarget = runtime.resolveBoolean(condition)
|
||||
if (shouldTarget) {
|
||||
brain.setMemory(MemoryModuleType.ATTACK_TARGET, livingEntity,
|
||||
runtime.resolveInt(maxAttackDuration).toLong()
|
||||
)
|
||||
brain.eraseMemory(MemoryModuleType.AVOID_TARGET)
|
||||
trackedEntity = livingEntity
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun onAttackTargetDataChanged(brain: BiggerBrain, attackData: CobblemonAttackTargetData?, labels: MutableSet<String>): Boolean {
|
||||
if (attackData != null) {
|
||||
// We smacked them, check if it's time for tactical retreat
|
||||
val livingEntity = brain.getMemory(MemoryModuleType.ATTACK_TARGET) ?: return true
|
||||
val runtime = mainThreadRuntime.withQueryValue("entity", (livingEntity).asMostSpecificMoLangValue())
|
||||
if (attackData.hitsLanded >= runtime.resolveInt(retaliationHitCount)) {
|
||||
// Justice served, carry on
|
||||
brain.eraseMemory(MemoryModuleType.ATTACK_TARGET)
|
||||
brain.eraseMemory(CobblemonMemories.ATTACK_TARGET_DATA)
|
||||
brain.setMemory(MemoryModuleType.AVOID_TARGET, trackedEntity)
|
||||
}
|
||||
}
|
||||
return true // Other listeners can handle it that's fine
|
||||
}
|
||||
|
||||
class Config : ObjectiveConfig {
|
||||
val speedMultiplier: ExpressionOrEntityVariable = Either.left("0.5".asExpression())
|
||||
val engageRange: ExpressionOrEntityVariable = Either.left("10.0".asExpression())
|
||||
val disengageRange: ExpressionOrEntityVariable = Either.left("10.0".asExpression())
|
||||
val condition: ExpressionOrEntityVariable = Either.left("10.0".asExpression())
|
||||
val maxAttackDuration: ExpressionOrEntityVariable = Either.left("300".asExpression())
|
||||
val retaliationHitCount: ExpressionOrEntityVariable = Either.left("1".asExpression())
|
||||
override fun getVariables(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): List<MoLangConfigVariable> {
|
||||
return listOf(condition, speedMultiplier, engageRange, disengageRange, maxAttackDuration, retaliationHitCount).asVariables()
|
||||
}
|
||||
|
||||
override fun create(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): Objective {
|
||||
return Defensive(
|
||||
condition = condition.asSimplifiedExpression(entity),
|
||||
speedMultiplier = speedMultiplier.asSimplifiedExpression(entity),
|
||||
engageRange = engageRange.asSimplifiedExpression(entity),
|
||||
disengageRange = disengageRange.asSimplifiedExpression(entity),
|
||||
maxAttackDuration = maxAttackDuration.asSimplifiedExpression(entity),
|
||||
retaliationHitCount = retaliationHitCount.asSimplifiedExpression(entity),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
-147
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.biggerbrain.objective
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.BiggerBrain
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.Distraction
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.distraction.comfortDistraction
|
||||
import com.cobblemon.mod.common.api.ai.biggerbrain.fixation.EntityFixation
|
||||
import com.cobblemon.mod.common.api.ai.config.objective.ObjectiveConfig
|
||||
import com.cobblemon.mod.common.api.ai.resolveFloat
|
||||
import com.cobblemon.mod.common.api.ai.resolveInt
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.FlagSpeciesFeature
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.level.GameRules
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.state.predicate.BlockStatePredicate
|
||||
|
||||
/**
|
||||
* The baa's eat the graa's
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since January 9th, 2025
|
||||
*/
|
||||
class EatGrass(
|
||||
val cooldownTicks: Int,
|
||||
val eatGrassChance: Float
|
||||
) : Objective {
|
||||
var fixation: EntityFixation? = null
|
||||
val grassPredicate = BlockStatePredicate.forBlock(Blocks.GRASS_BLOCK)
|
||||
var remainingCooldownTicks = cooldownTicks
|
||||
|
||||
override fun getDescription(entity: LivingEntity) = "Eat grass"
|
||||
|
||||
override fun perform(
|
||||
entity: LivingEntity,
|
||||
brain: BiggerBrain,
|
||||
activeObjectiveTags: MutableSet<String>
|
||||
): ObjectiveStatus {
|
||||
if (brain.isFixation(fixation)) {
|
||||
return ObjectiveStatus.FIXATED
|
||||
} else if (entity !is PokemonEntity) {
|
||||
return ObjectiveStatus.INVALID
|
||||
} else if (!brain.canDistract(comfortDistraction)) {
|
||||
return ObjectiveStatus.BLOCKED
|
||||
} else if (remainingCooldownTicks > 0) {
|
||||
remainingCooldownTicks--
|
||||
return ObjectiveStatus.ACTIVE
|
||||
}
|
||||
|
||||
val world = entity.level() as ServerLevel
|
||||
|
||||
entity.pokemon.getFeature<FlagSpeciesFeature>(DataKeys.HAS_BEEN_SHEARED)?.enabled?.takeIf { it } ?: run {
|
||||
return ObjectiveStatus.INACTIVE
|
||||
}
|
||||
|
||||
if (world.random.nextFloat() > eatGrassChance) {
|
||||
return ObjectiveStatus.ACTIVE
|
||||
} else {
|
||||
val blockPos = entity.blockPosition()
|
||||
|
||||
// Are we not even on a grass block? Alright don't bother
|
||||
if (!grassPredicate.test(world.getBlockState(blockPos)) && !world.getBlockState(blockPos.below()).`is`(Blocks.GRASS_BLOCK)) {
|
||||
return ObjectiveStatus.ACTIVE
|
||||
}
|
||||
|
||||
fixation = brain.fixate(EatGrassFixation(this))
|
||||
entity.playAnimation("eat")
|
||||
world.broadcastEntityEvent(entity, 10.toByte())
|
||||
return ObjectiveStatus.FIXATED
|
||||
}
|
||||
}
|
||||
|
||||
class EatGrassFixation(val objective: EatGrass) : EntityFixation {
|
||||
var timer = 40
|
||||
override fun getDescription(entity: LivingEntity) = "Eating grass"
|
||||
override fun canDistract(distraction: Distraction, entity: LivingEntity) = distraction.isComfort || distraction.isDamage || distraction.isForce
|
||||
override fun tick(entity: LivingEntity, brain: BiggerBrain): Boolean {
|
||||
timer--
|
||||
if (timer <= 0) {
|
||||
entity as PokemonEntity
|
||||
val world = entity.level() as ServerLevel
|
||||
val blockPos = entity.blockPosition()
|
||||
if (objective.grassPredicate.test(world.getBlockState(blockPos)) ) {
|
||||
if (world.gameRules.getBoolean(GameRules.RULE_MOBGRIEFING)) {
|
||||
world.destroyBlock(blockPos, false)
|
||||
}
|
||||
entity.ate()
|
||||
objective.remainingCooldownTicks = objective.cooldownTicks
|
||||
} else if (world.getBlockState(blockPos.below()).`is`(Blocks.GRASS_BLOCK)) {
|
||||
val below = blockPos.below()
|
||||
if (world.gameRules.getBoolean(GameRules.RULE_MOBGRIEFING)) {
|
||||
world.levelEvent(2001, below, Block.getId(Blocks.GRASS_BLOCK.defaultBlockState()))
|
||||
world.setBlock(below, Blocks.DIRT.defaultBlockState(), 2)
|
||||
}
|
||||
|
||||
entity.ate()
|
||||
objective.remainingCooldownTicks = objective.cooldownTicks
|
||||
}
|
||||
}
|
||||
return timer > 0
|
||||
}
|
||||
}
|
||||
|
||||
class Config : ObjectiveConfig {
|
||||
var cooldownTicks: ExpressionOrEntityVariable = Either.left("400".asExpression())
|
||||
var eatGrassChance: ExpressionOrEntityVariable = Either.left("1/400".asExpression())
|
||||
|
||||
override fun getVariables(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
) = listOf(
|
||||
cooldownTicks,
|
||||
eatGrassChance
|
||||
).asVariables()
|
||||
|
||||
override fun create(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): Objective? {
|
||||
val cooldownTicks = cooldownTicks.resolveInt(behaviourConfigurationContext.runtime)
|
||||
val eatGrassChance = eatGrassChance.resolveFloat(behaviourConfigurationContext.runtime)
|
||||
return if (eatGrassChance == 0F) {
|
||||
null
|
||||
} else {
|
||||
EatGrass(
|
||||
cooldownTicks = cooldownTicks,
|
||||
eatGrassChance = eatGrassChance
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user