Compare commits

..
Author SHA1 Message Date
Tyzillion a077e74bf2 When you wish upon a star
Makes no difference who you are
Anything your heart desires
Will come to you
If your heart is in your dream
No request is too extreme
When you wish upon a star
As dreamers do
Fate is kind
She brings to those who love
The sweet fulfillment of
Their secret longing
Like a bolt out of the blue
Fate steps in and sees you through
When you wish upon a star
Your dreams come true
2024-02-18 14:25:47 -05:00
Lily 763f1de793 forgot to push this mb 2024-02-16 22:34:31 -05:00
Lily 62a95b93c5 begin implementing falling stars 2024-02-16 14:48:20 -05:00
Lily 7991f70c09 Merge remote-tracking branch 'origin/dynamax' into dynamax 2024-02-16 14:48:07 -05:00
Lily 70d393a899 begin implementing falling stars 2024-02-16 14:47:58 -05:00
Lily 5bace46aa6 begin implementing falling stars 2024-02-13 21:51:28 -05:00
Lily c5fb411636 Merge branch 'sega_bass_pro_fishing_2' into dynamax
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonEntities.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonItems.kt
#	fabric/src/main/kotlin/com/cobblemon/mod/fabric/client/CobblemonFabricClient.kt
#	forge/src/main/kotlin/com/cobblemon/mod/forge/client/CobblemonForgeClient.kt
2024-02-13 20:59:18 -05:00
Lily 9a8159ee30 start on dynamax 2024-02-13 20:07:29 -05:00
Plastered_Crab acc6f119e1 - Magikarps getting reeled in now land in front of the player instead of behind the player (for battle reasons) 2024-02-13 16:45:22 -08:00
Plastered_Crab 932a2c375c - Begin different reel-in trajectories for fishing up Magikarps 2024-02-13 14:46:42 -08:00
Nick 142eebe9e6 Apply model predicates, starting with Pokerod 2024-02-09 22:07:43 -08:00
jeffw773 36f19c9180 - Xp is rewarded to player for fishing up Pokemon 2024-02-09 21:15:10 -08:00
jeffw773 beb8fed6bd - Pokeball Bobber now renders correctly when cast out with Pokerod
- Luck of the Sea and Lure get read correctly from the rod and factor into the spawn bucket chosen
2024-02-09 14:17:13 -08:00
jeffw773 142284a17c - Pokemon rarity is altered by Luck of the Sea 2024-02-08 21:18:41 -08:00
jeffw773 f1ea86362a - Fixed fishing spawns being able to check if sky is actually visible.
- added isOcean to biomes to Magikarp
2024-02-07 18:28:42 -08:00
Paul ec3361ad91 Added basic fishing spawn detail for Magikarp and use the world pool for fishing because ehhh 2024-02-03 12:16:53 +10:00
Paul ca7c36ce15 Added trigger spawning with a fishing implementation 2024-02-03 12:13:38 +10:00
jeffw773 f7c73728d7 - Added some newer spawning stuff and added battle initiation after fished up mon 2024-02-02 16:38:15 -08:00
jeffw773 1992a23edc Merge branch 'main' into sega_bass_pro_fishing_2 2024-02-02 13:39:02 -08:00
jeffw773 dad28135cc - Brief changes to particle count based on rarity reeled in 2024-01-18 14:32:43 -08:00
jeffw773 e41d13dd53 - Pokerod now uses config values for rarity buckets and access biome spawn pools 2024-01-14 23:02:33 -08:00
jeffw773 64cae53d82 - Pokerod foundation laid out for having chance to spawn Pokemon instead of getting item as well as rarity chance started 2024-01-14 00:11:12 -08:00
dhi_holo c9bf0bd8d7 Merge branch 'sega_bass_pro_fishing_2' of https://gitlab.com/cable-mc/cobblemon into sega_bass_pro_fishing_2 2024-01-14 13:36:53 +10:00
dhi_holo 97d2047aee It's a Tool, It's a Rod
makes pokerod be held correctly, and adds second model file for the cast variation, when that is implemented.
2024-01-14 13:36:04 +10:00
jeffw773 811f8abed7 - Added override for model of pokerod when cast 2024-01-13 19:27:22 -08:00
jeffw773 ab02a54f28 - Finally the Pokerod is starting to work! (it is backwards tho) 2024-01-13 19:08:36 -08:00
jeffw773 6e0c1aefcc - More testing fishing code for pokerod 2024-01-13 13:55:02 -08:00
jeffw773 e887b6c43c - Some code for fishing testing again 2024-01-13 12:16:38 -08:00
jeffw773 25172c2bc9 - Some code for fishing testing 2024-01-13 11:23:38 -08:00
jeffw773 929b90173a - Some code for fishing testing 2024-01-12 11:58:02 -08:00
jeffw773 70a65f6ffe - Testing code 2024-01-12 07:39:21 -08:00
jeffw773 db7d3f01d8 - Starting implementation on fishing 2024-01-12 07:39:20 -08:00
543 changed files with 2745 additions and 13826 deletions
+1 -4
View File
@@ -33,7 +33,4 @@ common/src/main/resources/assets/cobblemon/showdown
# Generated files
*/generated/resources/*
/fabric/src/generated/resources/cobblemon-common.accesswidener
/.ignored/
# MacOS
.DS_Store
/.ignored/
-17
View File
@@ -20,14 +20,6 @@
- Added effects for many Poké Balls when sending out Pokémon or capturing.
- Added a new send-out ball toss animation that showcases the ball used for the Pokémon.
- Added simple move animations for Pokémon in battle with a proof of concept for more complicated animations.
- Added the EV Boosting Feathers.
- Added Type Gems.
- Added various new tags for searchability and better compatibility.
- Added Gilded Chests, available in all Apricorn colors.
- Added Relic Coins, Relic Coin Pouches, and Relic Coin Sacks.
- Added Gimmighoul.
- Using Relic Coins, you can increase Gimmighoul's Coin Stash. Upon reaching 999, it can be evolved into Gholdengo.
- Additionally, if you give Gimmighoul a Netherite Scrap, you can increase its Netherite Stash. Who knows what might happen if it fills up?
### Changes
- Pokémon now transition more smoothly between different poses.
@@ -40,8 +32,6 @@
- Updated movesets to add Gen 9 DLC moves.
- Apricorn Sprouts can now be planted directly on Apricorn leaves to create a new Apricorn of the same color.
- Added tooltips to interaction GUIs to make it clearer what they do.
- Poké Ball recipes now use tags for their center ingredient, rather than specificied Copper Ingot, Iron Ingot, Gold Ingot, and Diamond, allowing for further datapack customisation.
- Using the run button in battle will now actually flee the battle.
### Fixes
- Re-added the recipe for the Iron Vitamin.
@@ -56,12 +46,6 @@
- Fixed Poké Balls freezing in an open state if you look away when it's meant to close.
- Adds a translation string name to the Empty Pokeball entity.
- Fixed very many issues with Bedrock particle effects.
- Fixed Arbok patterns not being as specific in spawning as they were intended.
- Fixed Pokémon not avoiding danger at all when pathfinding.
- Fixed Sobble line not being able to swim or breathe underwater.
- Fixed incompatibility with [Just Enough Resources](https://modrinth.com/mod/just-enough-resources-jer).
- Fixed incompatibility with [Visual Overhaul](https://modrinth.com/mod/visual-overhaul).
- Fixed an issue that allowed Pokemon to spawn on rails.
### Developer
- Significantly changed the way properties in PokemonEntity work. This could break some plugins (not in a big way, but changes will be needed).
@@ -73,7 +57,6 @@
- Made PokemonProperties.parse more interoperable with Java.
- Added the ``HeldItemEvent``, this comes with 2 implementation ``HeldItemEvent.Pre`` and ``HeldItemEvent.Post``.
- API to support dynamic lighting in any mod that implements this feature has been added to all Species & Forms, see LightingData class for details.
- Added a Mixin for the BrewingStandScreenHandler to fix the incorrect handling of quickMove in Fabric.
### Datapack & Resourcepack Creators
- The maximum amount of fossils that can fit in the Fossil Analyzer can be adjusted in the config.
@@ -1,33 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.CobblemonItems;
import net.minecraft.entity.mob.PiglinBrain;
import net.minecraft.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(PiglinBrain.class)
public class PiglinBarterMixin {
@Inject(method = "acceptsForBarter", at = @At(value = "RETURN"), cancellable = true)
private static void cobblemon$acceptsForBarter(ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
if(!ci.getReturnValue()) {
//TODO: Make a tag?
if(stack.isOf(CobblemonItems.RELIC_COIN_POUCH))
ci.setReturnValue(true);
}
}
}
@@ -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;
import com.cobblemon.mod.common.CobblemonItems;
import net.minecraft.entity.mob.PiglinEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(PiglinEntity.class)
public class PiglinEntityMixin {
@Redirect(method = "equipToOffHand", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;isOf(Lnet/minecraft/item/Item;)Z"))
public boolean cobblemon$isValidBarteringItem(ItemStack stack, Item item) {
//TODO: Make a tag?
return stack.isOf(item) || stack.isOf(CobblemonItems.RELIC_COIN_POUCH);
}
}
@@ -19,7 +19,6 @@ import com.cobblemon.mod.common.api.drop.ItemDropEntry
import com.cobblemon.mod.common.api.events.CobblemonEvents.BATTLE_VICTORY
import com.cobblemon.mod.common.api.events.CobblemonEvents.DATA_SYNCHRONIZED
import com.cobblemon.mod.common.api.events.CobblemonEvents.EVOLUTION_COMPLETE
import com.cobblemon.mod.common.api.events.CobblemonEvents.HELD_ITEM_UPDATED
import com.cobblemon.mod.common.api.events.CobblemonEvents.LEVEL_UP_EVENT
import com.cobblemon.mod.common.api.events.CobblemonEvents.POKEMON_CAPTURED
import com.cobblemon.mod.common.api.events.CobblemonEvents.TRADE_COMPLETED
@@ -35,7 +34,9 @@ import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffectRegistry
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceCalculator
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroups
import com.cobblemon.mod.common.api.pokemon.experience.StandardExperienceCalculator
import com.cobblemon.mod.common.api.pokemon.feature.*
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.SpeciesFeatures
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
@@ -45,8 +46,13 @@ import com.cobblemon.mod.common.api.scheduling.ServerRealTimeTaskTracker
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
import com.cobblemon.mod.common.api.spawning.BestSpawner
import com.cobblemon.mod.common.api.spawning.CobblemonSpawningProspector
import com.cobblemon.mod.common.api.spawning.WorldSlice
import com.cobblemon.mod.common.api.spawning.context.AreaContextResolver
import com.cobblemon.mod.common.api.spawning.context.AreaSpawningContext
import com.cobblemon.mod.common.api.spawning.context.calculators.AreaSpawningContextCalculator
import com.cobblemon.mod.common.api.spawning.context.calculators.AreaSpawningInput
import com.cobblemon.mod.common.api.spawning.prospecting.SpawningProspector
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
import com.cobblemon.mod.common.api.starter.StarterHandler
import com.cobblemon.mod.common.api.storage.PokemonStoreManager
import com.cobblemon.mod.common.api.storage.adapter.conversions.ReforgedConversion
@@ -93,7 +99,6 @@ import com.cobblemon.mod.common.pokemon.aspects.SHINY_ASPECT
import com.cobblemon.mod.common.pokemon.evolution.variants.BlockClickEvolution
import com.cobblemon.mod.common.pokemon.feature.TagSeasonResolver
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
import com.cobblemon.mod.common.pokemon.misc.GimmighoulStashHandler
import com.cobblemon.mod.common.pokemon.properties.HiddenAbilityPropertyType
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
import com.cobblemon.mod.common.pokemon.properties.tags.PokemonFlagProperty
@@ -101,13 +106,7 @@ import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
import com.cobblemon.mod.common.sherds.CobblemonSherds
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
import com.cobblemon.mod.common.trade.TradeManager
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.ifDedicatedServer
import com.cobblemon.mod.common.util.isLaterVersion
import com.cobblemon.mod.common.util.party
import com.cobblemon.mod.common.util.removeAmountIf
import com.cobblemon.mod.common.util.server
import com.cobblemon.mod.common.util.*
import com.cobblemon.mod.common.world.feature.CobblemonPlacedFeatures
import com.cobblemon.mod.common.world.feature.ore.CobblemonOrePlacedFeatures
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
@@ -130,8 +129,8 @@ import net.minecraft.entity.data.TrackedDataHandlerRegistry
import net.minecraft.item.Items
import net.minecraft.item.NameTagItem
import net.minecraft.registry.RegistryKey
import net.minecraft.sound.SoundCategory
import net.minecraft.util.WorldSavePath
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
import org.apache.logging.log4j.LogManager
@@ -254,7 +253,6 @@ object Cobblemon {
SpeciesFeatures.types["choice"] = ChoiceSpeciesFeatureProvider::class.java
SpeciesFeatures.types["flag"] = FlagSpeciesFeatureProvider::class.java
SpeciesFeatures.types["integer"] = IntSpeciesFeatureProvider::class.java
SpeciesFeatures.register(
DataKeys.CAN_BE_MILKED,
@@ -45,18 +45,6 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
@JvmField
val HANGING_SIGN: BlockEntityType<CobblemonHangingSignBlockEntity> = this.create("hanging_sign", BlockEntityType.Builder.create(::CobblemonHangingSignBlockEntity, CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN).build(null))
@JvmField
val GILDED_CHEST: BlockEntityType<GildedChestBlockEntity> = this.create("chest", BlockEntityType.Builder.create(::GildedChestBlockEntity,
CobblemonBlocks.GILDED_CHEST,
CobblemonBlocks.BLUE_GILDED_CHEST,
CobblemonBlocks.YELLOW_GILDED_CHEST,
CobblemonBlocks.PINK_GILDED_CHEST,
CobblemonBlocks.BLACK_GILDED_CHEST,
CobblemonBlocks.WHITE_GILDED_CHEST,
CobblemonBlocks.GREEN_GILDED_CHEST,
CobblemonBlocks.GIMMIGHOUL_CHEST
).build(null))
@JvmField
val FOSSIL_MULTIBLOCK: BlockEntityType<FossilMultiblockEntity> = this.create("fossil_multiblock",
BlockEntityType.Builder.create({ pos, state -> FossilMultiblockEntity(pos, state, FossilMultiblockBuilder(pos)) },
@@ -77,4 +65,10 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
CobblemonBlocks.FOSSIL_ANALYZER
).build(null)
)
@JvmField
val DYNITE_ORE: BlockEntityType<DyniteOreBlockEntity> = this.create("dynite_ore",
BlockEntityType.Builder.create(::DyniteOreBlockEntity, CobblemonBlocks.DYNITE_ORE)
.build(null)
)
}
@@ -22,7 +22,6 @@ import com.cobblemon.mod.common.mixin.invoker.*
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.block.chest.GildedChestBlock
import com.cobblemon.mod.common.block.sign.CobblemonHangingSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonWallHangingSignBlock
@@ -97,6 +96,15 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
@JvmField
val DEEPSLATE_WATER_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_water_stone_ore")
@JvmField
val DYNITE_ORE = this.create("dynite_ore", DyniteOreBlock(
AbstractBlock.Settings.create()
.mapColor(MapColor.BRIGHT_RED)
.strength(4.5f, 3f)
.requiresTool()
.sounds(BlockSoundGroup.METAL)
))
// Apricorns
@JvmField
val APRICORN_LOG = log("apricorn_log", arg2 = MapColor.BROWN)
@@ -152,11 +160,11 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
val YELLOW_APRICORN_SAPLING = this.create("yellow_apricorn_sapling", ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.YELLOW))
@JvmField
val MEDICINAL_LEEK = this.create("medicinal_leek", MedicinalLeekBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DULL_RED).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MEDICINAL_LEEK_SOUNDS)))
val MEDICINAL_LEEK = this.create("medicinal_leek", MedicinalLeekBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DULL_RED).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
@JvmField
val ENERGY_ROOT = this.create("energy_root", EnergyRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DIRT_BROWN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.ENERGY_ROOT_SOUNDS)))
val ENERGY_ROOT = this.create("energy_root", EnergyRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DIRT_BROWN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.ROOTS)))
@JvmField
val BIG_ROOT = this.create("big_root", BigRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.BIG_ROOT_SOUNDS)))
val BIG_ROOT = this.create("big_root", BigRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.ROOTS)))
@JvmField
val REVIVAL_HERB = this.create("revival_herb", RevivalHerbBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).mapColor(MapColor.DARK_GREEN).burnable().noCollision().breakInstantly().sounds(BlockSoundGroup.CROP)))
@@ -192,7 +200,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
.mapColor(MapColor.TERRACOTTA_ORANGE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
@@ -200,7 +207,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
.mapColor(MapColor.LIGHT_BLUE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
@@ -208,7 +214,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
.mapColor(MapColor.TERRACOTTA_BLACK)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@@ -227,99 +232,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
@JvmField
val YELLOW_APRICORN = apricornBlock("yellow_apricorn", Apricorn.YELLOW)
@JvmField
val RELIC_COIN_POUCH = create(
"relic_coin_pouch",
CoinPouchBlock(
AbstractBlock.Settings.create()
.sounds(CobblemonSounds.COIN_POUCH_SOUNDS)
.pistonBehavior(PistonBehavior.DESTROY)
.strength(0.4f)
.nonOpaque(), true
)
)
@JvmField
val RELIC_COIN_SACK = create(
"relic_coin_sack",
CoinPouchBlock(
AbstractBlock.Settings.create()
.sounds(CobblemonSounds.COIN_POUCH_SOUNDS)
.pistonBehavior(PistonBehavior.DESTROY)
.strength(0.4f), false
))
@JvmField
val GILDED_CHEST = create(
"gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.RED
)
)
@JvmField
val BLUE_GILDED_CHEST = create(
"blue_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.BLUE
)
)
@JvmField
val BLACK_GILDED_CHEST = create(
"black_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.BLACK
)
)
@JvmField
val YELLOW_GILDED_CHEST = create(
"yellow_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.YELLOW
)
)
@JvmField
val WHITE_GILDED_CHEST = create(
"white_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.WHITE
)
)
@JvmField
val GREEN_GILDED_CHEST = create(
"green_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.GREEN
)
)
@JvmField
val PINK_GILDED_CHEST = create(
"pink_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.PINK
)
)
@JvmField
val GIMMIGHOUL_CHEST = create(
"gimmighoul_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.FAKE
)
)
@JvmField
val MONITOR = create(
"monitor",
@@ -352,7 +264,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
RestorationTankBlock(
AbstractBlock.Settings.create()
.mapColor(MapColor.IRON_GRAY)
.sounds(BlockSoundGroup.GLASS)
.sounds(BlockSoundGroup.METAL)
.pistonBehavior(PistonBehavior.BLOCK)
.requiresTool()
.strength(5.0F, 6.0F)
@@ -387,17 +299,17 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
)
@JvmField
val RED_MINT = create("red_mint", MintBlock(MintType.RED, AbstractBlock.Settings.create().mapColor(MapColor.RED).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
val RED_MINT = create("red_mint", MintBlock(MintType.RED, AbstractBlock.Settings.create().mapColor(MapColor.RED).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
@JvmField
val BLUE_MINT = create("blue_mint", MintBlock(MintType.BLUE, AbstractBlock.Settings.create().mapColor(MapColor.BLUE).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
val BLUE_MINT = create("blue_mint", MintBlock(MintType.BLUE, AbstractBlock.Settings.create().mapColor(MapColor.BLUE).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
@JvmField
val CYAN_MINT = create("cyan_mint", MintBlock(MintType.CYAN, AbstractBlock.Settings.create().mapColor(MapColor.CYAN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
val CYAN_MINT = create("cyan_mint", MintBlock(MintType.CYAN, AbstractBlock.Settings.create().mapColor(MapColor.CYAN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
@JvmField
val PINK_MINT = create("pink_mint", MintBlock(MintType.PINK, AbstractBlock.Settings.create().mapColor(MapColor.PINK).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
val PINK_MINT = create("pink_mint", MintBlock(MintType.PINK, AbstractBlock.Settings.create().mapColor(MapColor.PINK).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
@JvmField
val GREEN_MINT = create("green_mint", MintBlock(MintType.GREEN, AbstractBlock.Settings.create().mapColor(MapColor.GREEN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
val GREEN_MINT = create("green_mint", MintBlock(MintType.GREEN, AbstractBlock.Settings.create().mapColor(MapColor.GREEN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
@JvmField
val WHITE_MINT = create("white_mint", MintBlock(MintType.WHITE, AbstractBlock.Settings.create().mapColor(MapColor.WHITE).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
val WHITE_MINT = create("white_mint", MintBlock(MintType.WHITE, AbstractBlock.Settings.create().mapColor(MapColor.WHITE).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
@JvmField
val PASTURE = create(
@@ -538,7 +450,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
private fun berryBlock(name: String): BerryBlock {
val identifier = cobblemonResource("${name}_berry")
val block = this.create(identifier.path, BerryBlock(identifier, AbstractBlock.Settings.copy(Blocks.WHEAT).dynamicBounds().sounds(CobblemonSounds.BERRY_BUSH_SOUNDS).strength(0.2F)))
val block = this.create(identifier.path, BerryBlock(identifier, AbstractBlock.Settings.copy(Blocks.WHEAT).dynamicBounds().sounds(BlockSoundGroup.CROP).strength(0.2F)))
this.berries[identifier] = block
return block
}
@@ -11,7 +11,9 @@ package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.entity.boat.CobblemonBoatEntity
import com.cobblemon.mod.common.entity.boat.CobblemonChestBoatEntity
import com.cobblemon.mod.common.entity.fallingstar.FallingStarEntity
import com.cobblemon.mod.common.entity.generic.GenericBedrockEntity
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.platform.PlatformRegistry
@@ -75,6 +77,24 @@ object CobblemonEntities : PlatformRegistry<Registry<EntityType<*>>, RegistryKey
.build(GENERIC_BEDROCK_ENTITY_KEY.toString())
)
@JvmField
val FALLING_STAR_ENTITY_KEY = cobblemonResource("falling_star")
@JvmField
val FALLING_STAR_ENTITY: EntityType<FallingStarEntity> = this.create(
FALLING_STAR_ENTITY_KEY.path,
EntityType.Builder.create({ _, world -> FallingStarEntity(world) }, SpawnGroup.MISC)
.build(FALLING_STAR_ENTITY_KEY.toString())
)
@JvmField
val POKE_BOBBER_KEY = cobblemonResource("poke_bobber")
@JvmField
val POKE_BOBBER: EntityType<PokeRodFishingBobberEntity> = this.create(
POKE_BOBBER_KEY.path,
EntityType.Builder.create(::PokeRodFishingBobberEntity, SpawnGroup.MISC).setDimensions(0.5F, 0.5F).maxTrackingRange(10)
.build(POKE_BOBBER_KEY.toString())
)
fun registerAttributes(consumer: (EntityType<out LivingEntity>, DefaultAttributeContainer.Builder) -> Unit) {
consumer(POKEMON, PokemonEntity.createAttributes())
}
@@ -29,6 +29,7 @@ import com.cobblemon.mod.common.item.berry.PortionHealingBerryItem
import com.cobblemon.mod.common.item.berry.StatusCuringBerryItem
import com.cobblemon.mod.common.item.berry.VolatileCuringBerryItem
import com.cobblemon.mod.common.item.interactive.*
import com.cobblemon.mod.common.item.interactive.PotionItem
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.pokeball.PokeBall
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
@@ -37,6 +38,7 @@ import net.minecraft.block.Block
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.effect.StatusEffectInstance
import net.minecraft.entity.effect.StatusEffects
import net.minecraft.item.*
import net.minecraft.item.BlockItem
import net.minecraft.item.FoodComponent
import net.minecraft.item.HangingSignItem
@@ -229,22 +231,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
val APRICORN_SIGN = this.create("apricorn_sign", SignItem(Item.Settings().maxCount(16), CobblemonBlocks.APRICORN_SIGN, CobblemonBlocks.APRICORN_WALL_SIGN))
@JvmField
val APRICORN_HANGING_SIGN = this.create("apricorn_hanging_sign", HangingSignItem(CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN, Item.Settings().maxCount(16)))
@JvmField
val GILDED_CHEST = this.create("gilded_chest", BlockItem(CobblemonBlocks.GILDED_CHEST, Item.Settings()))
@JvmField
val BLUE_GILDED_CHEST = this.create("blue_gilded_chest", BlockItem(CobblemonBlocks.BLUE_GILDED_CHEST, Item.Settings()))
@JvmField
val YELLOW_GILDED_CHEST = this.create("yellow_gilded_chest", BlockItem(CobblemonBlocks.YELLOW_GILDED_CHEST, Item.Settings()))
@JvmField
val PINK_GILDED_CHEST = this.create("pink_gilded_chest", BlockItem(CobblemonBlocks.PINK_GILDED_CHEST, Item.Settings()))
@JvmField
val BLACK_GILDED_CHEST = this.create("black_gilded_chest", BlockItem(CobblemonBlocks.BLACK_GILDED_CHEST, Item.Settings()))
@JvmField
val WHITE_GILDED_CHEST = this.create("white_gilded_chest", BlockItem(CobblemonBlocks.WHITE_GILDED_CHEST, Item.Settings()))
@JvmField
val GREEN_GILDED_CHEST = this.create("green_gilded_chest", BlockItem(CobblemonBlocks.GREEN_GILDED_CHEST, Item.Settings()))
@JvmField
val GIMMIGHOUL_CHEST = this.create("gimmighoul_chest", BlockItem(CobblemonBlocks.GIMMIGHOUL_CHEST, Item.Settings()))
@JvmField
val RESTORATION_TANK = blockItem("restoration_tank", CobblemonBlocks.RESTORATION_TANK)
@@ -396,18 +382,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val ZINC = create("zinc", VitaminItem(Stats.SPECIAL_DEFENCE))
@JvmField
val GENIUS_FEATHER = create("genius_feather", FeatherItem(Stats.SPECIAL_ATTACK))
@JvmField
val SWIFT_FEATHER = create("swift_feather", FeatherItem(Stats.SPEED))
@JvmField
val HEALTH_FEATHER = create("health_feather", FeatherItem(Stats.HP))
@JvmField
val RESIST_FEATHER = create("resist_feather", FeatherItem(Stats.DEFENCE))
@JvmField
val MUSCLE_FEATHER = create("muscle_feather", FeatherItem(Stats.ATTACK))
@JvmField
val CLEVER_FEATHER = create("clever_feather", FeatherItem(Stats.SPECIAL_DEFENCE))
@JvmField
val MEDICINAL_LEEK = create("medicinal_leek", MedicinalLeekItem(CobblemonBlocks.MEDICINAL_LEEK, Item.Settings().food(FoodComponent.Builder().snack().hunger(1).saturationModifier(0.2f).build())))
@JvmField
val ROASTED_LEEK = create("roasted_leek", Item(Item.Settings().food(FoodComponent.Builder().snack().hunger(3).saturationModifier(0.3f).build())))
@@ -606,6 +580,9 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val NETHER_FIRE_STONE_ORE = blockItem("nether_fire_stone_ore", CobblemonBlocks.NETHER_FIRE_STONE_ORE)
@JvmField
val DYNITE_ORE = blockItem("dynite_ore", CobblemonBlocks.DYNITE_ORE)
@JvmField
val DAWN_STONE = noSettingsItem("dawn_stone")
@JvmField
@@ -761,19 +738,19 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val ARMOR_FOSSIL = noSettingsItem("armor_fossil")
@JvmField
val FOSSILIZED_BIRD = noSettingsItem("fossilized_bird")
val BIRD_FOSSIL = noSettingsItem("bird_fossil")
@JvmField
val CLAW_FOSSIL = noSettingsItem("claw_fossil")
@JvmField
val COVER_FOSSIL = noSettingsItem("cover_fossil")
@JvmField
val FOSSILIZED_DINO = noSettingsItem("fossilized_dino")
val DINO_FOSSIL = noSettingsItem("dino_fossil")
@JvmField
val DOME_FOSSIL = noSettingsItem("dome_fossil")
@JvmField
val FOSSILIZED_DRAKE = noSettingsItem("fossilized_drake")
val DRAKE_FOSSIL = noSettingsItem("drake_fossil")
@JvmField
val FOSSILIZED_FISH = noSettingsItem("fossilized_fish")
val FISH_FOSSIL = noSettingsItem("fish_fossil")
@JvmField
val HELIX_FOSSIL = noSettingsItem("helix_fossil")
@JvmField
@@ -849,53 +826,12 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
SmithingTemplateItem.of(CobblemonArmorTrims.AUTOMATON)
)
@JvmField
val POKEROD = pokerodItem("pokerod")
// Misc
@JvmField
val POKEMON_MODEL = this.create("pokemon_model", PokemonItem())
@JvmField
val RELIC_COIN = noSettingsItem("relic_coin")
@JvmField
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)
// Type Gems
@JvmField
val NORMAL_GEM = noSettingsItem("normal_gem")
@JvmField
val FIRE_GEM = noSettingsItem("fire_gem")
@JvmField
val WATER_GEM = noSettingsItem("water_gem")
@JvmField
val GRASS_GEM = noSettingsItem("grass_gem")
@JvmField
val ELECTRIC_GEM = noSettingsItem("electric_gem")
@JvmField
val ICE_GEM = noSettingsItem("ice_gem")
@JvmField
val FIGHTING_GEM = noSettingsItem("fighting_gem")
@JvmField
val POISON_GEM = noSettingsItem("poison_gem")
@JvmField
val GROUND_GEM = noSettingsItem("ground_gem")
@JvmField
val FLYING_GEM = noSettingsItem("flying_gem")
@JvmField
val PSYCHIC_GEM = noSettingsItem("psychic_gem")
@JvmField
val BUG_GEM = noSettingsItem("bug_gem")
@JvmField
val ROCK_GEM = noSettingsItem("rock_gem")
@JvmField
val GHOST_GEM = noSettingsItem("ghost_gem")
@JvmField
val DRAGON_GEM = noSettingsItem("dragon_gem")
@JvmField
val DARK_GEM = noSettingsItem("dark_gem")
@JvmField
val STEEL_GEM = noSettingsItem("steel_gem")
@JvmField
val FAIRY_GEM = noSettingsItem("fairy_gem")
private fun blockItem(name: String, block: Block): BlockItem = this.create(name, BlockItem(block, Item.Settings()))
@@ -914,6 +850,12 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
private fun candyItem(name: String, calculator: CandyItem.Calculator): CandyItem = this.create(name, CandyItem(calculator))
private fun pokerodItem(name: String): PokerodItem {
var settings = Item.Settings()
val item = create(name, PokerodItem(settings))
return item
}
private fun heldItem(name: String, remappedName: String? = null): CobblemonItem = create(
name,
CobblemonItem(Item.Settings()).also {
@@ -82,12 +82,9 @@ import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyCallbackPa
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyMoveCallbackPacket
import com.cobblemon.mod.common.net.messages.client.data.AbilityRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.data.BerryRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.data.GlobalSpeciesFeatureSyncPacket
import com.cobblemon.mod.common.net.messages.client.data.MovesRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.data.PropertiesCompletionRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.data.SpeciesFeatureAssignmentSyncPacket
import com.cobblemon.mod.common.net.messages.client.data.SpeciesRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.data.StandardSpeciesFeatureSyncPacket
import com.cobblemon.mod.common.net.messages.client.data.UnlockReloadPacket
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
@@ -135,7 +132,6 @@ import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
import com.cobblemon.mod.common.net.messages.client.ui.SummaryUIPacket
import com.cobblemon.mod.common.net.messages.server.*
import com.cobblemon.mod.common.net.messages.server.battle.BattleSelectActionsPacket
import com.cobblemon.mod.common.net.messages.server.battle.FleeBattlePacket
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.callback.move.MoveSelectCancelledPacket
@@ -171,7 +167,6 @@ import com.cobblemon.mod.common.net.messages.server.trade.UpdateTradeOfferPacket
import com.cobblemon.mod.common.net.serverhandling.ChallengeHandler
import com.cobblemon.mod.common.net.serverhandling.RequestInteractionsHandler
import com.cobblemon.mod.common.net.serverhandling.battle.BattleSelectActionsHandler
import com.cobblemon.mod.common.net.serverhandling.battle.FleeBattlePacketHandler
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.callback.move.MoveSelectCancelledHandler
@@ -253,7 +248,6 @@ object CobblemonNetwork : NetworkManager {
this.createClientBound(PokemonStateUpdatePacket.ID, PokemonStateUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(TetheringUpdatePacket.ID, TetheringUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(TradeableUpdatePacket.ID, TradeableUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(SpeciesFeatureUpdatePacket.ID, SpeciesFeatureUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(OriginalTrainerUpdatePacket.ID, OriginalTrainerUpdatePacket::decode, PokemonUpdatePacketHandler())
// Evolution start
@@ -320,9 +314,6 @@ object CobblemonNetwork : NetworkManager {
this.createClientBound(PropertiesCompletionRegistrySyncPacket.ID, PropertiesCompletionRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(UnlockReloadPacket.ID, UnlockReloadPacket::decode, UnlockReloadPacketHandler)
this.createClientBound(BerryRegistrySyncPacket.ID, BerryRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(StandardSpeciesFeatureSyncPacket.ID, StandardSpeciesFeatureSyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(GlobalSpeciesFeatureSyncPacket.ID, GlobalSpeciesFeatureSyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(SpeciesFeatureAssignmentSyncPacket.ID, SpeciesFeatureAssignmentSyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(NaturalMaterialRegistrySyncPacket.ID, NaturalMaterialRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(FossilRegistrySyncPacket.ID, FossilRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
@@ -409,7 +400,6 @@ object CobblemonNetwork : NetworkManager {
this.createServerBound(BattleSelectActionsPacket.ID, BattleSelectActionsPacket::decode, BattleSelectActionsHandler)
this.createServerBound(SpectateBattlePacket.ID, SpectateBattlePacket::decode, SpectateBattleHandler)
this.createServerBound(RemoveSpectatorPacket.ID, RemoveSpectatorPacket::decode, RemoveSpectatorHandler)
this.createServerBound(FleeBattlePacket.ID, FleeBattlePacket::decode, FleeBattlePacketHandler)
// Trade
this.createServerBound(AcceptTradeRequestPacket.ID, AcceptTradeRequestPacket::decode, AcceptTradeRequestHandler)
@@ -16,7 +16,6 @@ import net.minecraft.registry.RegistryKey
import net.minecraft.registry.RegistryKeys
import net.minecraft.sound.BlockSoundGroup
import net.minecraft.sound.SoundEvent
import net.minecraft.sound.SoundEvents
object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Registry<SoundEvent>>, SoundEvent>() {
@@ -85,8 +84,6 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
val MEDICINE_PILLS_USE = this.create("medicine_pills.use")
@JvmField
val MEDICINE_SPRAY_USE = this.create("medicine_spray.use")
@JvmField
val MEDICINE_FEATHER_USE = this.create("medicine_feather.use")
@JvmField
val BERRY_HARVEST = this.create("berry.harvest")
@@ -121,14 +118,6 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
@JvmField
val FOSSIL_MACHINE_UNPROTECTED = this.create("fossilmachine.unprotected")
@JvmField
val COIN_POUCH_BREAK = this.create("coin_pouch.break")
@JvmField
val COIN_POUCH_HIT = this.create("coin_pouch.hit")
@JvmField
val COIN_POUCH_STEP = this.create("coin_pouch.step")
@JvmField
val COIN_POUCH_PLACE = this.create("coin_pouch.place")
@JvmField
val TUMBLESTONE_BREAK = this.create("tumblestone.break")
@JvmField
@@ -140,52 +129,6 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
@JvmField
val TUMBLESTONE_STEP = this.create("tumblestone.step")
@JvmField
val GIMMIGHOUL_GIVE_ITEM_SMALL = this.create("gimmighoul.give_item_small")
@JvmField
val GIMMIGHOUL_REVEAL = this.create("gimmighoul.reveal")
@JvmField
val BERRY_BUSH_BREAK = this.create("berry_bush.break")
@JvmField
val BERRY_BUSH_PLACE = this.create("berry_bush.place")
@JvmField
val BIG_ROOT_BREAK = this.create("big_root.break")
@JvmField
val ENERGY_ROOT_PLACE = this.create("energy_root.place")
@JvmField
val MINT_BREAK = this.create("mint.break")
@JvmField
val MINT_PLACE = this.create("mint.place")
@JvmField
val MEDICINAL_LEEK_BREAK = this.create("medicinal_leek.break")
@JvmField
val MEDICINAL_LEEK_PLACE = this.create("medicinal_leek.plant")
@JvmField
val GILDED_CHEST_OPEN = this.create("gilded_chest.open")
@JvmField
val GILDED_CHEST_CLOSE = this.create("gilded_chest.close")
@JvmField
val GILDED_CHEST_STEP = this.create("gilded_chest.step")
@JvmField
val GILDED_CHEST_HIT = this.create("gilded_chest.hit")
@JvmField
val GILDED_CHEST_BREAK = this.create("gilded_chest.break")
@JvmField
val GILDED_CHEST_PLACE = this.create("gilded_chest.place")
@JvmField
val COIN_POUCH_SOUNDS = BlockSoundGroup(1f, 1f,
COIN_POUCH_BREAK,
COIN_POUCH_STEP,
COIN_POUCH_PLACE,
COIN_POUCH_HIT,
COIN_POUCH_STEP
)
@JvmField
val IMPACT_NORMAL = this.create("impact.normal")
@JvmField
@@ -241,59 +184,5 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
TUMBLESTONE_STEP
)
@JvmField
val BERRY_BUSH_SOUNDS = BlockSoundGroup(1f, 1f,
BERRY_BUSH_BREAK,
SoundEvents.BLOCK_GRASS_STEP,
BERRY_BUSH_PLACE,
SoundEvents.BLOCK_GRASS_HIT,
SoundEvents.BLOCK_GRASS_STEP
)
@JvmField
val BIG_ROOT_SOUNDS = BlockSoundGroup(1f, 1f,
BIG_ROOT_BREAK,
SoundEvents.BLOCK_ROOTS_STEP,
SoundEvents.BLOCK_ROOTS_PLACE,
SoundEvents.BLOCK_ROOTS_HIT,
SoundEvents.BLOCK_ROOTS_FALL
)
@JvmField
val ENERGY_ROOT_SOUNDS = BlockSoundGroup(1f, 1f,
SoundEvents.BLOCK_ROOTS_BREAK,
SoundEvents.BLOCK_ROOTS_STEP,
ENERGY_ROOT_PLACE,
SoundEvents.BLOCK_ROOTS_HIT,
SoundEvents.BLOCK_ROOTS_FALL
)
@JvmField
val MEDICINAL_LEEK_SOUNDS = BlockSoundGroup(1f, 1f,
MEDICINAL_LEEK_BREAK,
SoundEvents.BLOCK_GRASS_STEP,
MEDICINAL_LEEK_PLACE,
SoundEvents.BLOCK_GRASS_HIT,
SoundEvents.BLOCK_GRASS_FALL
)
@JvmField
val MINT_SOUNDS = BlockSoundGroup(1f, 1f,
MINT_BREAK,
SoundEvents.BLOCK_GRASS_STEP,
MINT_PLACE,
SoundEvents.BLOCK_GRASS_HIT,
SoundEvents.BLOCK_GRASS_FALL
)
@JvmField
val GILDED_CHEST_SOUNDS = BlockSoundGroup(1f, 1f,
GILDED_CHEST_BREAK,
GILDED_CHEST_STEP,
GILDED_CHEST_PLACE,
GILDED_CHEST_HIT,
GILDED_CHEST_STEP
)
private fun create(name: String): SoundEvent = this.create(name, SoundEvent.of(cobblemonResource(name)))
}
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.api.drop
import com.cobblemon.mod.common.api.events.CobblemonEvents.LOOT_DROPPED
import com.cobblemon.mod.common.api.events.drops.LootDroppedEvent
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.entity.LivingEntity
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.server.world.ServerWorld
@@ -89,8 +88,6 @@ class DropTable {
amount: IntRange = this.amount
) {
val drops = getDrops(amount).toMutableList()
val heldItem = (entity as PokemonEntity).pokemon.heldItemNoCopy()
if (!heldItem.isEmpty) entity.dropItem(heldItem.item)
LOOT_DROPPED.postThen(
event = LootDroppedEvent(this, player, entity, drops),
ifSucceeded = { it.drops.forEach { it.drop(entity, world, pos, player) } }
@@ -33,7 +33,6 @@ import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionCompleteEv
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionDisplayEvent
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionTestedEvent
import com.cobblemon.mod.common.api.events.pokemon.interaction.ExperienceCandyUseEvent
import com.cobblemon.mod.common.api.events.pokemon.interaction.HeldItemUpdatedEvent
import com.cobblemon.mod.common.api.events.pokemon.interaction.PokemonInteractionGUICreationEvent
import com.cobblemon.mod.common.api.events.starter.StarterChosenEvent
import com.cobblemon.mod.common.api.events.storage.ReleasePokemonEvent
@@ -67,8 +66,6 @@ object CobblemonEvents {
val EVOLUTION_COMPLETE = EventObservable<EvolutionCompleteEvent>()
@JvmField
val POKEMON_NICKNAMED = CancelableObservable<PokemonNicknamedEvent>()
@JvmField
val HELD_ITEM_UPDATED = CancelableObservable<HeldItemUpdatedEvent>()
@JvmField
val THROWN_POKEBALL_HIT = CancelableObservable<ThrownPokeballHitEvent>()
@@ -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.api.events.pokemon.interaction
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.entity.LivingEntity
import net.minecraft.item.ItemStack
/**
* Event published when a held item is being updated on a [Pokemon].
* Cancelling the event will prevent any action from being taken on
* the Pokémon.
*
* [newItem] differs from [originalStack] in that the former is a
* one-sized version of the original (Pokémon cannot hold stacks) and
* changing it in any way will not affect the original item held by
* the player.
*
* @author Whatsy, Hiroku
* @since November 13th, 2023
*/
data class HeldItemUpdatedEvent(
val cause: LivingEntity?,
val pokemon: Pokemon,
val originalStack: ItemStack,
val decrement: Boolean,
val oldItem: ItemStack,
val newItem: ItemStack
) : Cancelable()
@@ -19,7 +19,6 @@ import net.minecraft.util.ActionResult
import net.minecraft.util.Hand
import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.math.BlockPos
import net.minecraft.world.BlockView
import net.minecraft.world.World
/**
@@ -78,11 +77,6 @@ abstract class MultiblockBlock(properties: Settings) : BlockWithEntity(propertie
return BlockRenderType.MODEL
}
override fun getPickStack(world: BlockView, pos: BlockPos, state: BlockState): ItemStack {
val blockEntity = world.getBlockEntity(pos) as? MultiblockEntity ?: return ItemStack.EMPTY
return if (blockEntity.multiblockStructure == null) super.getPickStack(world, pos, state) else ItemStack.EMPTY
}
abstract fun createMultiBlockEntity(pos: BlockPos, state: BlockState): FossilMultiblockEntity
}
@@ -34,10 +34,4 @@ interface PassiveEvolution : Evolution {
return false
}
/**
* If the evolution will disappear once the conditions are no longer met.
*/
val permanent: Boolean
}
@@ -11,12 +11,10 @@ package com.cobblemon.mod.common.api.pokemon.feature
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
import com.cobblemon.mod.common.api.properties.CustomPokemonPropertyType
import com.cobblemon.mod.common.client.gui.summary.featurerenderers.SummarySpeciesFeatureRenderer
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.substitute
import com.google.gson.JsonObject
import net.minecraft.nbt.NbtCompound
import net.minecraft.network.PacketByteBuf
/**
* A [SpeciesFeatureProvider] which is a string value selected from a fixed list of choices. Parameters exist
@@ -26,46 +24,15 @@ import net.minecraft.network.PacketByteBuf
* @since November 30th, 2022
*/
open class ChoiceSpeciesFeatureProvider(
override var keys: List<String>,
override val keys: List<String>,
var default: String? = null,
var choices: List<String> = listOf(),
var isAspect: Boolean = true,
var aspectFormat: String = "{{choice}}"
) : SynchronizedSpeciesFeatureProvider<StringSpeciesFeature>, CustomPokemonPropertyType<StringSpeciesFeature>, AspectProvider {
override var needsKey = true
override var visible = false
) : SpeciesFeatureProvider<StringSpeciesFeature>, CustomPokemonPropertyType<StringSpeciesFeature>, AspectProvider {
override val needsKey = true
fun getAspect(feature: StringSpeciesFeature) = aspectFormat.substitute("choice", feature.value)
override fun encode(buffer: PacketByteBuf) {
buffer.writeCollection(keys) { _, value -> buffer.writeString(value) }
buffer.writeNullable(default) { _, value -> buffer.writeString(value) }
buffer.writeCollection(choices) { _, value -> buffer.writeString(value) }
buffer.writeBoolean(isAspect)
buffer.writeString(aspectFormat)
buffer.writeBoolean(needsKey)
}
override fun decode(buffer: PacketByteBuf) {
keys = buffer.readList { buffer.readString() }
default = buffer.readNullable { buffer.readString() }
choices = buffer.readList { buffer.readString() }
isAspect = buffer.readBoolean()
aspectFormat = buffer.readString()
needsKey = buffer.readBoolean()
}
override fun getRenderer(pokemon: Pokemon): SummarySpeciesFeatureRenderer<StringSpeciesFeature>? {
return null
}
override fun invoke(buffer: PacketByteBuf, name: String): StringSpeciesFeature? {
return if (name in keys) {
StringSpeciesFeature(name, "").also { it.decode(buffer) }
} else {
null
}
}
fun getAllAspects(): MutableList<String> {
val aspects = choices.toMutableList()
choices.forEach {
@@ -78,10 +45,10 @@ open class ChoiceSpeciesFeatureProvider(
internal constructor(): this(emptyList())
override fun get(pokemon: Pokemon) = pokemon.getFeature<StringSpeciesFeature>(keys.first())
fun get(pokemon: Pokemon) = pokemon.getFeature<StringSpeciesFeature>(keys.first())
override fun invoke(pokemon: Pokemon): StringSpeciesFeature? {
val existing = get(pokemon)
val existing = pokemon.getFeature<StringSpeciesFeature>(keys.first())
return if (existing != null && existing.value in choices) {
existing
} else {
@@ -121,7 +88,7 @@ open class ChoiceSpeciesFeatureProvider(
override fun provide(pokemon: Pokemon): Set<String> {
return if (isAspect) {
get(pokemon)?.let { setOf(getAspect(it)) } ?: emptySet()
pokemon.getFeature<StringSpeciesFeature>(keys.first())?.let { setOf(getAspect(it)) } ?: emptySet()
} else {
emptySet()
}
@@ -12,12 +12,10 @@ import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
import com.cobblemon.mod.common.api.properties.CustomPokemonPropertyType
import com.cobblemon.mod.common.client.gui.summary.featurerenderers.SummarySpeciesFeatureRenderer
import com.cobblemon.mod.common.pokemon.Pokemon
import com.google.gson.JsonObject
import kotlin.random.Random
import net.minecraft.nbt.NbtCompound
import net.minecraft.network.PacketByteBuf
/**
* A simple [SpeciesFeature] that is a true/false flag value. It implements [CustomPokemonProperty] for use in
@@ -28,7 +26,7 @@ import net.minecraft.network.PacketByteBuf
* @author Hiroku
* @since May 13th, 2022
*/
open class FlagSpeciesFeature(override val name: String) : SynchronizedSpeciesFeature, CustomPokemonProperty {
open class FlagSpeciesFeature(override val name: String) : SpeciesFeature, CustomPokemonProperty {
constructor(name: String, enabled: Boolean): this(name) {
this.enabled = enabled
}
@@ -55,14 +53,6 @@ open class FlagSpeciesFeature(override val name: String) : SynchronizedSpeciesFe
return this
}
override fun encode(buffer: PacketByteBuf) {
buffer.writeBoolean(enabled)
}
override fun decode(buffer: PacketByteBuf) {
enabled = buffer.readBoolean()
}
override fun asString() = "$name=$enabled"
override fun apply(pokemon: Pokemon) {
@@ -81,37 +71,11 @@ open class FlagSpeciesFeature(override val name: String) : SynchronizedSpeciesFe
override fun matches(pokemon: Pokemon) = pokemon.getFeature<FlagSpeciesFeature>(name)?.enabled == enabled
}
class FlagSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<FlagSpeciesFeature>, CustomPokemonPropertyType<FlagSpeciesFeature>, AspectProvider {
override var keys: List<String> = emptyList()
// Uses get() = true because that way there's no backing field. It MUST be true, this way no JSON trickery will overwrite it
class FlagSpeciesFeatureProvider : SpeciesFeatureProvider<FlagSpeciesFeature>, CustomPokemonPropertyType<FlagSpeciesFeature>, AspectProvider {
override val keys: List<String>
override val needsKey get() = true
var default: String? = null
var isAspect = true
override var visible: Boolean = false
override fun invoke(buffer: PacketByteBuf, name: String): FlagSpeciesFeature? {
return if (name in keys) {
FlagSpeciesFeature(name).also { it.decode(buffer) }
} else {
null
}
}
override fun encode(buffer: PacketByteBuf) {
buffer.writeCollection(keys) { _, value -> buffer.writeString(value) }
buffer.writeNullable(default) { _, value -> buffer.writeString(value) }
buffer.writeBoolean(isAspect)
}
override fun decode(buffer: PacketByteBuf) {
keys = buffer.readList { it.readString() }
default = buffer.readNullable { it.readString() }
isAspect = buffer.readBoolean()
}
override fun getRenderer(pokemon: Pokemon): SummarySpeciesFeatureRenderer<FlagSpeciesFeature>? {
return null
}
val isAspect = true
override fun examples() = setOf("true", "false")
@@ -130,10 +94,8 @@ class FlagSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<FlagSpecie
constructor(vararg keys: String) : this(keys.toList())
override fun get(pokemon: Pokemon) = pokemon.getFeature<FlagSpeciesFeature>(keys.first())
override fun invoke(pokemon: Pokemon): FlagSpeciesFeature? {
return get(pokemon)
return pokemon.getFeature(keys.first())
?: when (default) {
"random" -> FlagSpeciesFeature(keys.first(), Random.Default.nextBoolean())
in setOf("true", "false") -> FlagSpeciesFeature(keys.first(), default.toBoolean())
@@ -8,17 +8,13 @@
package com.cobblemon.mod.common.api.pokemon.feature
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
import com.cobblemon.mod.common.api.properties.CustomPokemonPropertyType
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.GlobalSpeciesFeatureSyncPacket
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.SpeciesFeatureProviderAdapter
import com.cobblemon.mod.common.util.adapters.Vec3dAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.Gson
import com.google.gson.GsonBuilder
@@ -28,7 +24,6 @@ import net.minecraft.nbt.NbtCompound
import net.minecraft.resource.ResourceType
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
import net.minecraft.util.math.Vec3d
/**
* A registry very similar to [SpeciesFeatures] but the [SpeciesFeatureProvider] contained within it
@@ -47,15 +42,11 @@ object GlobalSpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
override val gson: Gson = GsonBuilder()
.setPrettyPrinting()
.registerTypeAdapter(SpeciesFeatureProvider::class.java, SpeciesFeatureProviderAdapter)
.registerTypeAdapter(Vec3d::class.java, Vec3dAdapter)
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
.create()
override val typeToken: TypeToken<SpeciesFeatureProvider<*>> = TypeToken.get(SpeciesFeatureProvider::class.java)
override val resourcePath: String = "global_species_features"
override fun sync(player: ServerPlayerEntity) {
player.sendPacket(GlobalSpeciesFeatureSyncPacket(codeFeatures + resourceFeatures))
}
override fun sync(player: ServerPlayerEntity) {}
override fun reload(data: Map<Identifier, SpeciesFeatureProvider<*>>) {
resourceFeatures.keys.toList().forEach(this::unregister)
@@ -68,10 +59,6 @@ object GlobalSpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
fun getFeatures() = (resourceFeatures.keys + codeFeatures.keys).mapNotNull(this::getFeature)
fun loadOnClient(entries: Collection<Map.Entry<String, SpeciesFeatureProvider<*>>>) {
codeFeatures.putAll(entries.map { it.toPair() })
}
private fun register(name: String, provider: SpeciesFeatureProvider<*>, isCoded: Boolean) {
val mapping = if (isCoded) codeFeatures else resourceFeatures
if (provider is AspectProvider) {
@@ -1,181 +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.pokemon.feature
import com.cobblemon.mod.common.api.net.Decodable
import com.cobblemon.mod.common.api.net.Encodable
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
import com.cobblemon.mod.common.api.properties.CustomPokemonPropertyType
import com.cobblemon.mod.common.client.gui.summary.featurerenderers.BarSummarySpeciesFeatureRenderer
import com.cobblemon.mod.common.client.gui.summary.featurerenderers.SummarySpeciesFeatureRenderer
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.asTranslated
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.JsonObject
import com.google.gson.annotations.SerializedName
import net.minecraft.nbt.NbtCompound
import net.minecraft.network.PacketByteBuf
import net.minecraft.util.Identifier
import net.minecraft.util.math.Vec3d
/**
* A species feature value that's just an integer. Complex stuff.
* @author Hiroku
*/
class IntSpeciesFeature(override var name: String) : SynchronizedSpeciesFeature, CustomPokemonProperty {
var value = 0
constructor(): this("")
constructor(name: String, value: Int): this(name) {
this.value = value
}
override fun saveToNBT(pokemonNBT: NbtCompound): NbtCompound {
pokemonNBT.putInt(name, value)
return pokemonNBT
}
override fun loadFromNBT(pokemonNBT: NbtCompound): SynchronizedSpeciesFeature {
value = pokemonNBT.getInt(name)
return this
}
override fun saveToJSON(pokemonJSON: JsonObject): JsonObject {
pokemonJSON.addProperty(name, value)
return pokemonJSON
}
override fun loadFromJSON(pokemonJSON: JsonObject): SpeciesFeature {
value = pokemonJSON.get(name).asInt
return this
}
override fun encode(buffer: PacketByteBuf) {
buffer.writeInt(value)
}
override fun decode(buffer: PacketByteBuf) {
value = buffer.readInt()
}
override fun asString() = "$name=$value"
override fun apply(pokemon: Pokemon) {
val featureProvider = SpeciesFeatures.getFeature(name) ?: return
if (featureProvider in SpeciesFeatures.getFeaturesFor(pokemon.species)) {
val existingFeature = pokemon.getFeature<IntSpeciesFeature>(name)
if (existingFeature != null) {
existingFeature.value = value
} else {
pokemon.features.add(IntSpeciesFeature(name, value))
}
pokemon.updateAspects()
}
}
override fun matches(pokemon: Pokemon) = pokemon.getFeature<IntSpeciesFeature>(name)?.value == value
}
class IntSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<IntSpeciesFeature>, CustomPokemonPropertyType<IntSpeciesFeature> {
class DisplayData : Encodable, Decodable {
var name: String = ""
@SerializedName(value = "colour" /* fuck you we use real english */, alternate = ["color"])
var colour = Vec3d(255.0, 255.0, 255.0)
var underlay: Identifier? = null
var overlay: Identifier? = null
override fun decode(buffer: PacketByteBuf) {
name = buffer.readString()
colour = Vec3d(buffer.readDouble(), buffer.readDouble(), buffer.readDouble())
underlay = buffer.readNullable { buffer.readIdentifier() }
overlay = buffer.readNullable { buffer.readIdentifier() }
}
override fun encode(buffer: PacketByteBuf) {
buffer.writeString(name)
buffer.writeDouble(colour.x)
buffer.writeDouble(colour.y)
buffer.writeDouble(colour.z)
buffer.writeNullable(underlay) { _, value -> buffer.writeIdentifier(value) }
buffer.writeNullable(overlay) { _, value -> buffer.writeIdentifier(value) }
}
}
override var keys = listOf<String>()
// Uses get() = true because that way there's no backing field. It MUST be true, this way no JSON trickery will overwrite it
override val needsKey get() = true
override var visible = false
var default: Int? = null
var min = 0
var max = 100
var display: DisplayData? = null
override fun fromString(value: String?) = value?.toIntOrNull()?.takeIf { it in min..max }?.let { IntSpeciesFeature(keys.first(), it) }
override fun examples() = emptyList<String>()
override fun invoke(buffer: PacketByteBuf, name: String): IntSpeciesFeature? {
return if (name in keys) {
IntSpeciesFeature(name, buffer.readInt())
} else {
null
}
}
override fun invoke(pokemon: Pokemon): IntSpeciesFeature? {
return get(pokemon) ?: default?.let { IntSpeciesFeature(keys.first(), it) }
}
override fun invoke(nbt: NbtCompound): IntSpeciesFeature? {
return if (nbt.contains(keys.first())) {
IntSpeciesFeature(keys.first(), nbt.getInt(keys.first()))
} else {
null
}
}
override fun invoke(json: JsonObject): IntSpeciesFeature? {
return if (json.has(keys.first())) {
IntSpeciesFeature(keys.first(), json.get(keys.first()).asInt)
} else {
null
}
}
override fun get(pokemon: Pokemon) = pokemon.features.filterIsInstance<IntSpeciesFeature>().find { it.name in keys }
override fun encode(buffer: PacketByteBuf) {
buffer.writeCollection(keys) { _, value -> buffer.writeString(value) }
buffer.writeNullable(default) { _, value -> buffer.writeInt(value) }
buffer.writeInt(min)
buffer.writeInt(max)
buffer.writeNullable(display) { _, value -> value.encode(buffer) }
}
override fun decode(buffer: PacketByteBuf) {
keys = buffer.readList { buffer.readString() }
default = buffer.readNullable { buffer.readInt() }
min = buffer.readInt()
max = buffer.readInt()
display = buffer.readNullable { DisplayData().also { it.decode(buffer) } }
}
override fun getRenderer(pokemon: Pokemon): SummarySpeciesFeatureRenderer<IntSpeciesFeature>? {
return display?.let {
BarSummarySpeciesFeatureRenderer(
name = keys.first(),
displayName = it.name.asTranslated(),
min = min,
max = max,
colour = it.colour,
underlay = it.underlay ?: cobblemonResource("textures/gui/summary/summary_stats_other_bar.png"),
overlay = it.overlay ?: cobblemonResource("textures/gui/summary/summary_stats_generic_overlay.png"),
pokemon = pokemon
)
}
}
}
@@ -8,13 +8,10 @@
package com.cobblemon.mod.common.api.pokemon.feature
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.SpeciesFeatureAssignmentSyncPacket
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.Gson
import com.google.gson.GsonBuilder
@@ -41,24 +38,17 @@ object SpeciesFeatureAssignments : JsonDataRegistry<SpeciesFeatureAssignment> {
override val typeToken = TypeToken.get(SpeciesFeatureAssignment::class.java)
override val resourcePath = "species_feature_assignments"
private val assignments = mutableMapOf<Identifier, MutableSet<String>>()
private val assignments = mutableMapOf<String, MutableSet<String>>()
override fun sync(player: ServerPlayerEntity) {
player.sendPacket(SpeciesFeatureAssignmentSyncPacket(assignments))
}
override fun sync(player: ServerPlayerEntity) {}
override fun reload(data: Map<Identifier, SpeciesFeatureAssignment>) {
data.values.forEach {
it.pokemon.forEach { pokemon ->
assignments.getOrPut(pokemon.asIdentifierDefaultingNamespace()) { mutableSetOf() }.addAll(it.features)
assignments.getOrPut(pokemon) { mutableSetOf() }.addAll(it.features)
}
}
this.observable.emit(this)
}
fun loadOnClient(data: Map<Identifier, MutableSet<String>>) {
this.assignments.clear()
this.assignments.putAll(data)
}
fun getFeatures(species: Species) = assignments[species.resourceIdentifier] ?: emptySet()
fun getFeatures(species: Species) = assignments[species.showdownId()] ?: emptySet()
}
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.api.pokemon.feature
import com.cobblemon.mod.common.pokemon.Pokemon
import com.google.gson.JsonObject
import net.minecraft.nbt.NbtCompound
import net.minecraft.network.PacketByteBuf
/**
* A provider of [SpeciesFeature]s. These must be registered via [SpeciesFeatures] either programmatically or
@@ -8,17 +8,13 @@
package com.cobblemon.mod.common.api.pokemon.feature
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
import com.cobblemon.mod.common.api.properties.CustomPokemonPropertyType
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.StandardSpeciesFeatureSyncPacket
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.SpeciesFeatureProviderAdapter
import com.cobblemon.mod.common.util.adapters.Vec3dAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.Gson
import com.google.gson.GsonBuilder
@@ -26,7 +22,6 @@ import com.google.gson.reflect.TypeToken
import net.minecraft.resource.ResourceType
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
import net.minecraft.util.math.Vec3d
/**
* A registry for [SpeciesFeatureProvider]s. This is the backbone of species-specific data such as
@@ -53,15 +48,11 @@ object SpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
override val gson: Gson = GsonBuilder()
.setPrettyPrinting()
.registerTypeAdapter(SpeciesFeatureProvider::class.java, SpeciesFeatureProviderAdapter)
.registerTypeAdapter(Vec3d::class.java, Vec3dAdapter)
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
.create()
override val typeToken: TypeToken<SpeciesFeatureProvider<*>> = TypeToken.get(SpeciesFeatureProvider::class.java)
override val resourcePath: String = "species_features"
override fun sync(player: ServerPlayerEntity) {
player.sendPacket(StandardSpeciesFeatureSyncPacket(codeFeatures + resourceFeatures))
}
override fun sync(player: ServerPlayerEntity) {}
override fun reload(data: Map<Identifier, SpeciesFeatureProvider<*>>) {
resourceFeatures.keys.toList().forEach(this::unregister)
@@ -71,9 +62,6 @@ object SpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
fun getCodeFeature(name: String) = resourceFeatures[name]
fun getResourceFeature(name: String) = codeFeatures[name]
fun getFeature(name: String) = getCodeFeature(name) ?: getResourceFeature(name)
fun loadOnClient(entries: Collection<Map.Entry<String, SpeciesFeatureProvider<*>>>) {
codeFeatures.putAll(entries.map { it.toPair() })
}
fun getFeatures() = (resourceFeatures.keys + codeFeatures.keys).mapNotNull(this::getFeature)
fun getFeaturesFor(species: Species): List<SpeciesFeatureProvider<*>> {
@@ -12,7 +12,6 @@ import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
import com.cobblemon.mod.common.pokemon.Pokemon
import com.google.gson.JsonObject
import net.minecraft.nbt.NbtCompound
import net.minecraft.network.PacketByteBuf
/**
* A species feature value that is a string value.
@@ -23,7 +22,7 @@ import net.minecraft.network.PacketByteBuf
class StringSpeciesFeature(
override val name: String,
var value: String
) : SynchronizedSpeciesFeature, CustomPokemonProperty {
) : SpeciesFeature, CustomPokemonProperty {
override fun saveToNBT(pokemonNBT: NbtCompound): NbtCompound {
pokemonNBT.putString(name, value)
return pokemonNBT
@@ -44,14 +43,6 @@ class StringSpeciesFeature(
return this
}
override fun encode(buffer: PacketByteBuf) {
buffer.writeString(value)
}
override fun decode(buffer: PacketByteBuf) {
value = buffer.readString()
}
override fun asString() = "$name=$value"
override fun apply(pokemon: Pokemon) {
@@ -1,20 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.pokemon.feature
import com.cobblemon.mod.common.api.net.Decodable
import com.cobblemon.mod.common.api.net.Encodable
/**
* A species feature that can be synchronized to the client. These must be managed by a [SynchronizedSpeciesFeatureProvider].
*
* @author Hiroku
* @since November 13th, 2023
*/
interface SynchronizedSpeciesFeature : SpeciesFeature, Encodable, Decodable
@@ -1,33 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.pokemon.feature
import com.cobblemon.mod.common.api.net.Decodable
import com.cobblemon.mod.common.api.net.Encodable
import com.cobblemon.mod.common.client.gui.summary.featurerenderers.SummarySpeciesFeatureRenderer
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.network.PacketByteBuf
/**
* A species feature provider that will be synchronized to the client. For it to be renderable in the summary
* screen of a Pokémon it must also provide a [SummarySpeciesFeatureRenderer] in [getRenderer]. Note that you
* really don't want to initialize a renderer outside of that function call because if the server ever initializes
* it then you're going to get crashes on dedicated servers (this is a bad thing).
*
* @author Hiroku
* @since November 13th, 2023
*/
interface SynchronizedSpeciesFeatureProvider<T : SynchronizedSpeciesFeature> : SpeciesFeatureProvider<T>, Encodable, Decodable {
var visible: Boolean
operator fun invoke(buffer: PacketByteBuf, name: String): T?
/** Gets the feature from this Pokémon, if it has been created yet. */
fun get(pokemon: Pokemon): T?
/** Only run this from the client. */
fun getRenderer(pokemon: Pokemon): SummarySpeciesFeatureRenderer<T>?
}
@@ -29,7 +29,7 @@ import net.minecraft.util.math.Vec3d
* @since January 4th, 2023
*/
class BedrockParticle(
var texture: Identifier = Identifier("minecraft:textures/particles/bubble.png"),
var texture: Identifier = Identifier("minecraft:textures/particle/bubble.png"),
var material: ParticleMaterial = ParticleMaterial.ALPHA,
var uvMode: ParticleUVMode = StaticParticleUVMode(),
var sizeX: Expression = NumberExpression(0.15),
@@ -10,19 +10,8 @@ package com.cobblemon.mod.common.api.spawning
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.api.entity.Despawner
import com.cobblemon.mod.common.api.spawning.condition.AreaSpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.BasicSpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.GroundedSpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.SubmergedSpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.SurfaceSpawningCondition
import com.cobblemon.mod.common.api.spawning.context.AreaContextResolver
import com.cobblemon.mod.common.api.spawning.context.GroundedSpawningContext
import com.cobblemon.mod.common.api.spawning.context.LavafloorSpawningContext
import com.cobblemon.mod.common.api.spawning.context.SeafloorSpawningContext
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.context.SubmergedSpawningContext
import com.cobblemon.mod.common.api.spawning.context.SurfaceSpawningContext
import com.cobblemon.mod.common.api.spawning.condition.*
import com.cobblemon.mod.common.api.spawning.context.*
import com.cobblemon.mod.common.api.spawning.context.calculators.GroundedSpawningContextCalculator
import com.cobblemon.mod.common.api.spawning.context.calculators.LavafloorSpawningContextCalculator
import com.cobblemon.mod.common.api.spawning.context.calculators.SeafloorSpawningContextCalculator
@@ -32,6 +21,8 @@ import com.cobblemon.mod.common.api.spawning.context.calculators.SurfaceSpawning
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import com.cobblemon.mod.common.api.spawning.fallingstar.FallingStarSpawner
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawner
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.api.spawning.preset.BasicSpawnDetailPreset
import com.cobblemon.mod.common.api.spawning.preset.BestSpawnerConfig
@@ -83,6 +74,8 @@ object BestSpawner {
var config = BestSpawnerConfig()
val spawnerManagers = mutableListOf<SpawnerManager>(CobblemonWorldSpawnerManager)
var defaultPokemonDespawner: Despawner<PokemonEntity> = CobblemonAgingDespawner(getAgeTicks = { it.ticksLived })
lateinit var fishingSpawner: FishingSpawner
lateinit var starSpawner: FallingStarSpawner
fun loadConfig() {
LOGGER.info("Starting the Best Spawner...")
@@ -91,6 +84,8 @@ object BestSpawner {
SpawningCondition.register(SubmergedSpawningCondition.NAME, SubmergedSpawningCondition::class.java)
SpawningCondition.register(GroundedSpawningCondition.NAME, GroundedSpawningCondition::class.java)
SpawningCondition.register(SurfaceSpawningCondition.NAME, SurfaceSpawningCondition::class.java)
SpawningCondition.register(FishingSpawningCondition.NAME, FishingSpawningCondition::class.java)
SpawningCondition.register(FallingStarSpawningCondition.NAME, FallingStarSpawningCondition::class.java)
LOGGER.info("Loaded ${SpawningCondition.conditionTypes.size} spawning condition types.")
SpawningContextCalculator.register(GroundedSpawningContextCalculator)
@@ -104,6 +99,8 @@ object BestSpawner {
SpawningContext.register(name = "lavafloor", clazz = LavafloorSpawningContext::class.java, defaultCondition = GroundedSpawningCondition.NAME)
SpawningContext.register(name = "submerged", clazz = SubmergedSpawningContext::class.java, defaultCondition = SubmergedSpawningCondition.NAME)
SpawningContext.register(name = "surface", clazz = SurfaceSpawningContext::class.java, defaultCondition = SurfaceSpawningCondition.NAME)
SpawningContext.register(name = "fishing", clazz = FishingSpawningContext::class.java, defaultCondition = FishingSpawningCondition.NAME)
SpawningContext.register(name = "fallingstar", clazz = FallingStarSpawningContext::class.java, defaultCondition = FallingStarSpawningCondition.NAME)
LOGGER.info("Loaded ${SpawningContext.contexts.size} spawning context types.")
@@ -118,5 +115,7 @@ object BestSpawner {
fun onServerStarted() {
spawnerManagers.forEach(SpawnerManager::onServerStarted)
fishingSpawner = FishingSpawner()
starSpawner = FallingStarSpawner()
}
}
@@ -0,0 +1,23 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.condition
import com.cobblemon.mod.common.api.spawning.context.FallingStarSpawningContext
class FallingStarSpawningCondition: SpawningCondition<FallingStarSpawningContext>() {
override fun contextClass() = FallingStarSpawningContext::class.java
override fun fits(ctx: FallingStarSpawningContext): Boolean {
return true
}
companion object {
const val NAME = "fallingstar"
}
}
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.condition
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
import com.cobblemon.mod.common.api.spawning.context.FishingSpawningContext
import com.cobblemon.mod.common.util.itemRegistry
import net.minecraft.block.Block
import net.minecraft.item.Item
/**
* A spawning condition that applies to [FishingSpawningContext]s.
*
* @author Hiroku
* @since February 3rd, 2024
*/
class FishingSpawningCondition: SpawningCondition<FishingSpawningContext>() {
override fun contextClass() = FishingSpawningContext::class.java
var rod: RegistryLikeCondition<Item>? = null
var neededNearbyBlocks: MutableList<RegistryLikeCondition<Block>>? = null
override fun fits(ctx: FishingSpawningContext): Boolean {
if (!super.fits(ctx)) {
return false
} else if (rod != null && !rod!!.fits(ctx.rodItem ?: return false, ctx.world.itemRegistry)) {
return false
} else if (neededNearbyBlocks != null && neededNearbyBlocks!!.none { cond -> ctx.nearbyBlockTypes.any { cond.fits(it, ctx.blockRegistry) } }) {
return false
} else {
return true
}
}
companion object {
const val NAME = "fishing"
}
}
@@ -76,4 +76,51 @@ interface AreaContextResolver {
return contexts
}
// fun resolveFishing(
// spawner: Spawner,
// contextCalculators: List<AreaSpawningContextCalculator<*>>,
// slice: WorldSlice
// ): List<AreaSpawningContext> {
// var pos = BlockPos.Mutable(1, 2, 3)
// val input = AreaSpawningInput(spawner, pos, slice)
// val contexts = mutableListOf<AreaSpawningContext>()
//
// var x = slice.baseX
// var y = slice.baseY
// var z = slice.baseZ
//
// while (x < slice.baseX + slice.length) {
// while (y < slice.baseY + slice.height) {
// while (z < slice.baseZ + slice.width) {
// pos.set(x, y, z)
// val vec = pos.toVec3d()
// if (slice.nearbyEntityPositions.none { it.isInRange(vec, 50.0) && it != slice.cause.entity }) {
// val fittedContextCalculator = contextCalculators
// .firstOrNull { calc -> calc.fits(input) && input.spawner.influences.none { !it.isAllowedPosition(input.world, input.position, calc) } }
// if (fittedContextCalculator != null) {
// val context = fittedContextCalculator.calculate(input)
// if (context != null) {
// contexts.add(context)
// // The position BlockPos has been used in a context, editing the same one
// // will cause entities to spawn at the wrong location (buried in walls, usually)
// // I made it so that our context calculators specifically take a copy of the
// // BlockPos but it'd still be exposed in custom contexts so fixing it here too.
// pos = BlockPos.Mutable(1, 2, 3)
// input.position = pos
// }
// }
// }
// z++
// }
// y++
// z = slice.baseZ
// }
// x++
// y = slice.baseY
// z = slice.baseZ
// }
//
// return contexts
// }
}
@@ -0,0 +1,31 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.context
import com.cobblemon.mod.common.api.spawning.fallingstar.FallingStarSpawnCause
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.BlockPos
class FallingStarSpawningContext(
cause: FallingStarSpawnCause,
world: ServerWorld,
pos: BlockPos,
influences: MutableList<SpawningInfluence>
) : TriggerSpawningContext(
cause = cause,
world = world,
position = pos,
light = world.getLightLevel(pos),
skyLight = world.getLightLevel(pos.up()),
canSeeSky = world.isSkyVisibleAllowingSea(pos),
influences = influences
) {
}
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.context
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawnCause
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.util.getBlockStates
import com.cobblemon.mod.common.util.toVec3d
import net.minecraft.block.Block
import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Box
/**
* A spawning context that was generated for a fishing action.
*
* @author Hiroku
* @since February 3rd, 2024
*/
class FishingSpawningContext(
cause: FishingSpawnCause,
world: ServerWorld,
pos: BlockPos,
influences: MutableList<SpawningInfluence>
) : TriggerSpawningContext(
cause = cause,
world = world,
position = pos,
light = world.getLightLevel(pos),
skyLight = world.getLightLevel(pos.up()),
canSeeSky = world.isSkyVisibleAllowingSea(pos),
influences = influences
) {
val nearbyBlocks = world.getBlockStates(Box.of(pos.toVec3d(), 10.0, 10.0, 10.0))
val nearbyBlockTypes: List<Block> by lazy { nearbyBlocks.mapNotNull { it.block }.distinct() }
val rodStack = cause.rodStack
val rodItem = cause.rodItem
}
@@ -0,0 +1,34 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.context
import com.cobblemon.mod.common.api.spawning.SpawnCause
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.BlockPos
/**
* A spawning context relating to triggered spawning. Uses a single-point structure cache which is
* the only contribution of this implementation.
*
* @author Hiroku
* @since February 3rd, 2024
*/
open class TriggerSpawningContext(
override val cause: SpawnCause,
override val world: ServerWorld,
override val position: BlockPos,
override val light: Int,
override val skyLight: Int,
override val canSeeSky: Boolean,
override val influences: MutableList<SpawningInfluence>
) : SpawningContext() {
val triggerStructureCache = StructureChunkCache()
override fun getStructureCache(pos: BlockPos) = triggerStructureCache
}
@@ -0,0 +1,20 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.fallingstar
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.SpawnCause
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
import net.minecraft.entity.Entity
class FallingStarSpawnCause(
spawner: Spawner,
bucket: SpawnBucket,
entity: Entity?
) : SpawnCause(spawner, bucket, entity)
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.fallingstar
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
import com.cobblemon.mod.common.api.spawning.context.FallingStarSpawningContext
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.api.spawning.spawner.TriggerSpawner
import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.BlockPos
open class FallingStarSpawner(
override val name: String = "fallingstar",
pool: SpawnPool = CobblemonSpawnPools.WORLD_SPAWN_POOL
) : TriggerSpawner<FallingStarSpawnCause>(name, pool) {
override fun parseContext(cause: FallingStarSpawnCause, world: ServerWorld, pos: BlockPos): FallingStarSpawningContext? {
return FallingStarSpawningContext(cause, world, pos, influences)
}
}
@@ -0,0 +1,32 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.fishing
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.SpawnCause
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
import net.minecraft.entity.Entity
import net.minecraft.item.FishingRodItem
import net.minecraft.item.ItemStack
/**
* A spawning cause that is embellished with fishing information. Could probably also
* have the bobber entity or something.
*
* @author Hiroku
* @since February 3rd, 2024
*/
class FishingSpawnCause(
spawner: Spawner,
bucket: SpawnBucket,
entity: Entity?,
val rodStack: ItemStack
) : SpawnCause(spawner, bucket, entity) {
val rodItem = rodStack.item as? FishingRodItem
}
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.fishing
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
import com.cobblemon.mod.common.api.spawning.context.FishingSpawningContext
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.api.spawning.spawner.TriggerSpawner
import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.BlockPos
/**
* A spawner that takes in a [FishingSpawnCause] and spawns things.
*
* @author Hiroku
* @since February 3rd, 2024
*/
open class FishingSpawner(
override val name: String = "fishing",
pool: SpawnPool = CobblemonSpawnPools.WORLD_SPAWN_POOL
) : TriggerSpawner<FishingSpawnCause>(name, pool) {
override fun parseContext(cause: FishingSpawnCause, world: ServerWorld, pos: BlockPos): FishingSpawningContext? {
// Maybe confirm that it's water we're fishing in?
val ctx = FishingSpawningContext(
cause = cause,
world = world,
pos = pos,
influences = influences
)
return ctx
}
}
@@ -1,51 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.influence
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import net.minecraft.registry.tag.BlockTags
/**
* Implements a [SpawningInfluence] that prevents Pokémon spawning on certain blocks.
* This ensures that Pokémon don't spawn in areas that could disrupt player-built structures or mechanisms.
* The influence checks the block directly above the potential spawn location; if the block is in the restricted list,
* the spawn is disallowed.
*
* @author Aethen
* @since February 20th, 2024
*/
open class RestrictedSpawnBlocksInfluence
: SpawningInfluence {
// The list of blocks that Pokémon are not allowed to spawn on.
private val restrictedBlocks = BlockTags.RAILS
/**
* Affects the spawnable status of a Pokémon spawn detail.
* If the block directly above the spawn location is in the restricted list, the spawn is disallowed.
*
* @param detail The Pokémon spawn detail to be affected.
* @param ctx The context of the spawning event.
* @return `true` if the spawn is allowed, `false` if it is disallowed.
*/
override fun affectSpawnable(detail: SpawnDetail, ctx: SpawningContext): Boolean {
// If the spawn detail is not a Pokémon, it is not affected by this influence.
if (detail.type != "pokemon") return true
// Get the position of the potential spawn location.
val pokemonSpawnPos = ctx.position
// Examine the block immediately above the spawn block to check for a rail
// Potentially need a refactor if we ever want to check the spawn block itself.
return ctx.world.getBlockState(pokemonSpawnPos.withY(pokemonSpawnPos.y + 1)).isIn(restrictedBlocks).not()
}
}
@@ -13,10 +13,8 @@ import com.cobblemon.mod.common.api.spawning.CobblemonSpawnRules
import com.cobblemon.mod.common.api.spawning.SpawnerManager
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.api.spawning.influence.PlayerLevelRangeInfluence
import com.cobblemon.mod.common.api.spawning.influence.RestrictedSpawnBlocksInfluence
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.api.spawning.rules.SpawnRule
import com.cobblemon.mod.common.util.mutableLazy
import net.minecraft.server.network.ServerPlayerEntity
/**
@@ -28,31 +26,14 @@ import net.minecraft.server.network.ServerPlayerEntity
* @since February 14th, 2022
*/
object PlayerSpawnerFactory {
var spawns: SpawnPool by mutableLazy {
CobblemonSpawnPools.WORLD_SPAWN_POOL
}
/**
* The list of influences for a new [PlayerSpawner].
* The influences will be added to the spawner in the order they are added to this list.
*
* [PlayerLevelRangeInfluence] adjusts the level range of Pokémon that can spawn based on the player's level.
* [RestrictedSpawnBlocksInfluence] prevents Pokémon from spawning on certain blocks.
*/
var influenceBuilders = mutableListOf<(player: ServerPlayerEntity) -> SpawningInfluence?>({
PlayerLevelRangeInfluence(
it,
variation = 5
)
}, { RestrictedSpawnBlocksInfluence() })
var spawns: SpawnPool = CobblemonSpawnPools.WORLD_SPAWN_POOL
var influenceBuilders = mutableListOf<(player: ServerPlayerEntity) -> SpawningInfluence?>({ PlayerLevelRangeInfluence(it, variation = 5) })
fun create(spawnerManager: SpawnerManager, player: ServerPlayerEntity): PlayerSpawner {
val influences = influenceBuilders.mapNotNull { it(player) }
return PlayerSpawner(player, spawns, spawnerManager).also {
it.influences.addAll(influences)
it.influences.addAll(
CobblemonSpawnRules.rules.values.filter(SpawnRule::enabled).flatMap(SpawnRule::components)
)
it.influences.addAll(CobblemonSpawnRules.rules.values.filter(SpawnRule::enabled).flatMap(SpawnRule::components))
}
}
}
@@ -0,0 +1,51 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.spawner
import com.cobblemon.mod.common.api.spawning.SpawnCause
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.api.spawning.selection.FlatContextWeightedSelector
import com.cobblemon.mod.common.api.spawning.selection.SpawningSelector
import java.util.concurrent.CompletableFuture
import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.BlockPos
/**
* A type of spawner that occurs at a single point and provides its own means of generating a
* context from a particular cause and position. The trigger spawner must be directly called to
* spawn things (almost as if it was being triggered) as opposed to being scheduled on a ticker.
*
* @author Hiroku
* @since February 3rd, 2024
*/
abstract class TriggerSpawner<T : SpawnCause>(override val name: String, var spawns: SpawnPool) : Spawner {
private var selector: SpawningSelector = FlatContextWeightedSelector()
override val influences = mutableListOf<SpawningInfluence>()
open fun run(cause: T, world: ServerWorld, pos: BlockPos): CompletableFuture<*>? {
val context = parseContext(cause, world, pos) ?: return null
selector.select(this, listOf(context))?.let { (_, spawn) ->
val action = spawn.doSpawn(context)
action.complete()
return action.future
}
return null
}
/** Parses a context, if possible, from the given cause and position. */
abstract fun parseContext(cause: T, world: ServerWorld, pos: BlockPos): SpawningContext?
override fun canSpawn() = true
override fun getSpawningSelector() = selector
override fun setSpawningSelector(selector: SpawningSelector) { this.selector = selector }
override fun getSpawnPool() = spawns
override fun setSpawnPool(spawnPool: SpawnPool) { spawns = spawnPool }
}
@@ -11,14 +11,12 @@ package com.cobblemon.mod.common.api.storage.party
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.advancement.CobblemonCriteria
import com.cobblemon.mod.common.advancement.criterion.PartyCheckContext
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.api.pokemon.evolution.PassiveEvolution
import com.cobblemon.mod.common.api.storage.pc.PCStore
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.pokemon.OriginalTrainerType
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.activestate.ShoulderedState
import com.cobblemon.mod.common.pokemon.evolution.variants.LevelUpEvolution
import com.cobblemon.mod.common.util.*
import net.minecraft.nbt.NbtCompound
import net.minecraft.server.network.ServerPlayerEntity
@@ -125,12 +123,6 @@ open class PlayerPartyStore(
// Passive evolutions
pokemon.evolutions.filterIsInstance<PassiveEvolution>().forEach { it.attemptEvolution(pokemon) }
val removeList = mutableListOf<Evolution>()
pokemon.evolutionProxy.server().forEach {
if (!it.test(pokemon) && it is LevelUpEvolution && !it.permanent)
removeList.add(it)
}
removeList.forEach { pokemon.evolutionProxy.server().remove(it) }
}
// Friendship
// ToDo expand this down the line just a very basic implementation for the first releases
@@ -21,7 +21,6 @@ import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
import com.cobblemon.mod.common.net.messages.client.animation.PlayPoseableAnimationPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleHealthChangePacket
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
import com.cobblemon.mod.common.pokemon.evolution.progress.DamageTakenEvolutionProgress
import com.cobblemon.mod.common.pokemon.evolution.progress.RecoilEvolutionProgress
import com.cobblemon.mod.common.util.battleLang
@@ -71,26 +70,18 @@ class DamageInstruction(
}
battle.dispatch {
val pokemonEntity = battlePokemon.entity
if (!causedFaint && pokemonEntity != null) {
val pkt = PlayPoseableAnimationPacket(pokemonEntity.id, setOf("recoil"), emptySet())
pkt.sendToPlayersAround(
x = pokemonEntity.x,
y = pokemonEntity.y,
z = pokemonEntity.z,
worldKey = pokemonEntity.world.registryKey,
distance = 50.0
)
}
if (!causedFaint) {
if (pokemonEntity != null) {
RunPosableMoLangPacket(pokemonEntity.id, setOf("q.particle('cobblemon:hit', 'target')")).sendToPlayersAround(
x = pokemonEntity.x,
y = pokemonEntity.y,
z = pokemonEntity.z,
worldKey = pokemonEntity.world.registryKey,
distance = 50.0
)
battlePokemon.entity?.let { pokemonEntity ->
val pkt = PlayPoseableAnimationPacket(pokemonEntity.id, setOf("recoil"), emptySet())
pkt.sendToPlayersAround(
x = pokemonEntity.x,
y = pokemonEntity.y,
z = pokemonEntity.z,
worldKey = pokemonEntity.world.registryKey,
distance = 50.0
)
}
}
@@ -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.block
import net.minecraft.block.*
import net.minecraft.item.ItemPlacementContext
import net.minecraft.state.StateManager
import net.minecraft.state.property.BooleanProperty
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.util.shape.VoxelShape
import net.minecraft.util.shape.VoxelShapes
import net.minecraft.world.BlockView
import net.minecraft.world.WorldAccess
class CoinPouchBlock(settings: Settings, val small: Boolean) : HorizontalFacingBlock(settings) {
init {
this.defaultState = this.stateManager.defaultState
.with(NATURAL, false)
.with(FACING, Direction.NORTH)
}
override fun getOutlineShape(
state: BlockState?,
world: BlockView?,
pos: BlockPos?,
context: ShapeContext?
) = if (!small) super.getOutlineShape(state, world, pos, context) else {
VoxelShapes.cuboid(0.3125, 0.0, 0.3125, 0.6875, 0.3125, 0.6875)
}
override fun getPlacementState(ctx: ItemPlacementContext): BlockState? {
var blockState = defaultState
val worldView = ctx.world
val blockPos = ctx.blockPos
ctx.placementDirections.forEach { direction ->
if (direction.axis.isHorizontal) {
blockState = blockState.with(FACING, direction.opposite) as BlockState
if (blockState.canPlaceAt(worldView, blockPos)) {
return blockState
}
}
}
return null
}
@Deprecated("Deprecated in Java")
override fun getStateForNeighborUpdate(
state: BlockState,
direction: Direction,
neighborState: BlockState,
world: WorldAccess,
pos: BlockPos,
neighborPos: BlockPos
): BlockState {
return if (direction == state.get(FACING) && !state.canPlaceAt(world, pos)) Blocks.AIR.defaultState
else super.getStateForNeighborUpdate(state, direction, neighborState, world, pos, neighborPos)
}
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
builder.add(FACING, NATURAL)
}
companion object {
val NATURAL: BooleanProperty = BooleanProperty.of("natural")
}
}
@@ -0,0 +1,36 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block
import com.cobblemon.mod.common.CobblemonBlockEntities
import com.cobblemon.mod.common.block.entity.DyniteOreBlockEntity
import net.minecraft.block.BlockRenderType
import net.minecraft.block.BlockState
import net.minecraft.block.BlockWithEntity
import net.minecraft.block.entity.BlockEntity
import net.minecraft.block.entity.BlockEntityTicker
import net.minecraft.block.entity.BlockEntityType
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
class DyniteOreBlock(settings: Settings) : BlockWithEntity(settings) {
override fun createBlockEntity(pos: BlockPos, state: BlockState): BlockEntity {
return DyniteOreBlockEntity(pos, state)
}
override fun getRenderType(state: BlockState?) = BlockRenderType.MODEL
override fun <T : BlockEntity> getTicker(
world: World,
state: BlockState,
type: BlockEntityType<T>
): BlockEntityTicker<T>? {
return checkType(type, CobblemonBlockEntities.DYNITE_ORE, DyniteOreBlockEntity.TICKER::tick)
}
}
@@ -16,7 +16,6 @@ import com.cobblemon.mod.common.block.entity.RestorationTankBlockEntity
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockBuilder
import net.minecraft.block.*
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.ai.pathing.NavigationType
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.inventory.SidedInventory
import net.minecraft.item.ItemPlacementContext
@@ -217,11 +216,6 @@ class RestorationTankBlock(properties: Settings) : MultiblockBlock(properties),
override fun asString() = label
}
@Deprecated("Deprecated in Java")
override fun canPathfindThrough(state: BlockState?, world: BlockView?, pos: BlockPos?, type: NavigationType?): Boolean {
return false
}
companion object {
val PART = EnumProperty.of("part", TankPart::class.java)
val TRIGGERED = Properties.TRIGGERED
@@ -1,228 +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.block.chest
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.scheduling.afterOnServer
import com.cobblemon.mod.common.block.entity.GildedChestBlockEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.party
import com.cobblemon.mod.common.util.toVec3d
import net.minecraft.block.Block
import net.minecraft.block.BlockRenderType
import net.minecraft.block.BlockState
import net.minecraft.block.BlockWithEntity
import net.minecraft.block.Blocks
import net.minecraft.block.HorizontalFacingBlock
import net.minecraft.block.ShapeContext
import net.minecraft.entity.ai.pathing.NavigationType
import net.minecraft.entity.mob.PiglinBrain
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.ItemPlacementContext
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.sound.SoundCategory
import net.minecraft.state.StateManager
import net.minecraft.state.property.Properties
import net.minecraft.text.MutableText
import net.minecraft.text.Text
import net.minecraft.util.ActionResult
import net.minecraft.util.BlockMirror
import net.minecraft.util.BlockRotation
import net.minecraft.util.Hand
import net.minecraft.util.Identifier
import net.minecraft.util.ItemScatterer
import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.util.shape.VoxelShape
import net.minecraft.util.shape.VoxelShapes
import net.minecraft.world.BlockView
import net.minecraft.world.World
@Suppress("OVERRIDE_DEPRECATION")
class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWithEntity(settings) {
init {
defaultState = defaultState.with(Properties.HORIZONTAL_FACING, Direction.SOUTH)
}
companion object {
val POKEMON_ARGS = "gimmighoul"
val LEVEL_RANGE = 5..30
val SOUTH_OUTLINE = VoxelShapes.union(
VoxelShapes.cuboid(0.0, 0.0, 0.25, 1.0, 1.0, 0.9375)
)
val NORTH_OUTLINE = VoxelShapes.union(
VoxelShapes.cuboid(0.0, 0.0, 0.0625, 1.0, 1.0, 0.75)
)
val WEST_OUTLINE = VoxelShapes.union(
VoxelShapes.cuboid(0.0625, 0.0, 0.0, 0.75, 1.0, 1.0)
)
val EAST_OUTLINE = VoxelShapes.union(
VoxelShapes.cuboid(0.25, 0.0, 0.0, 0.9375, 1.0, 1.0)
)
}
override fun createBlockEntity(pos: BlockPos, state: BlockState) = GildedChestBlockEntity(pos, state, type)
override fun getOutlineShape(
state: BlockState,
world: BlockView,
pos: BlockPos,
context: ShapeContext
): VoxelShape {
return when (state.get(HorizontalFacingBlock.FACING)) {
Direction.NORTH -> NORTH_OUTLINE
Direction.SOUTH -> SOUTH_OUTLINE
Direction.WEST -> WEST_OUTLINE
else -> EAST_OUTLINE
}
}
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
super.appendProperties(builder)
builder.add(Properties.HORIZONTAL_FACING)
}
private val facingToYaw: HashMap<Direction, Float> = hashMapOf(
Direction.NORTH to -179.0F,
Direction.WEST to 90.0F,
Direction.SOUTH to 0.0F,
Direction.EAST to -90.0F
)
override fun getName(): MutableText {
return if (isFake()) Text.translatable("block.cobblemon.gilded_chest") else super.getName()
}
fun isFake() = (type == Type.FAKE)
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity) {
if (isFake()) {
if (player is ServerPlayerEntity) {
spawnPokemon(world, pos, state, player)
}
world.setBlockState(pos, Blocks.AIR.defaultState)
} else super.onBreak(world, pos, state, player)
}
private fun spawnPokemon(world: World, pos: BlockPos, state: BlockState, player: ServerPlayerEntity) : ActionResult {
val properties = "$POKEMON_ARGS lvl=${LEVEL_RANGE.random()}"
val pokemon = PokemonProperties.parse(properties)
val entity = pokemon.createEntity(world)
// The yaw based on the block's facing direction
val yaw = facingToYaw[state[HorizontalFacingBlock.FACING]] ?: 0.0F
entity.dataTracker.set(PokemonEntity.SPAWN_DIRECTION, facingToYaw[state[HorizontalFacingBlock.FACING]])
val offsetDir = state[HorizontalFacingBlock.FACING]
val vec = pos.toVec3d().add(offsetDir.offsetX * 0.1 + 0.5, 0.0, offsetDir.offsetZ * 0.1 + 0.5)
entity.refreshPositionAndAngles(vec.x, vec.y, vec.z, yaw, entity.pitch)
world.spawnEntity(entity)
world.removeBlock(pos, false)
afterOnServer(ticks = 2) {
if (player !in player.world.players) {
return@afterOnServer
}
val party = player.party()
if (!player.isCreative) {
entity.forceBattle(player)
} else {
world.playSound(null, pos, CobblemonSounds.GIMMIGHOUL_REVEAL, SoundCategory.NEUTRAL)
}
}
return ActionResult.SUCCESS
}
override fun onUse(
state: BlockState,
world: World,
pos: BlockPos,
player: PlayerEntity,
hand: Hand,
hit: BlockHitResult
): ActionResult {
if (isFake()) {
if (player is ServerPlayerEntity) {
return spawnPokemon(world, pos, state, player)
} else {
return ActionResult.SUCCESS
}
}
val entity = world.getBlockEntity(pos) as? GildedChestBlockEntity ?: return ActionResult.FAIL
if (world.getBlockState(pos.up()).isSolidBlock(world, pos.up())) return ActionResult.FAIL
player.openHandledScreen(entity)
if (!player.world.isClient) {
PiglinBrain.onGuardedBlockInteracted(player, true)
}
val state = entity.poseableState
state.currentModel?.let {
it.moveToPose(null, state, it.getPose("OPEN")!!)
}
return ActionResult.SUCCESS
}
override fun onStateReplaced(
state: BlockState,
world: World,
pos: BlockPos,
newState: BlockState,
moved: Boolean
) {
if (!state.isOf(newState.block)) {
val chest = world.getBlockEntity(pos) as GildedChestBlockEntity
ItemScatterer.spawn(world, pos, chest.inventoryContents)
}
}
override fun getRenderType(state: BlockState?) = BlockRenderType.ENTITYBLOCK_ANIMATED
override fun getPlacementState(blockPlaceContext: ItemPlacementContext): BlockState? {
// val abovePosition = blockPlaceContext.blockPos.up()
// val world = blockPlaceContext.world
// if (world.getBlockState(abovePosition).canReplace(blockPlaceContext) && !world.isOutOfHeightLimit(abovePosition)) {
return defaultState.with(HorizontalFacingBlock.FACING, blockPlaceContext.horizontalPlayerFacing.opposite)
// }
// return null
}
@Deprecated("Deprecated in Java")
override fun rotate(state: BlockState, rotation: BlockRotation): BlockState {
return state.with(
Properties.HORIZONTAL_FACING, rotation.rotate(
state.get(Properties.HORIZONTAL_FACING) as Direction
)
) as BlockState
}
override fun mirror(state: BlockState, mirror: BlockMirror): BlockState {
return state.rotate(mirror.getRotation(state.get(Properties.HORIZONTAL_FACING) as Direction))
}
enum class Type(val poserId: Identifier) {
RED(cobblemonResource("gilded_chest")),
BLUE(cobblemonResource("blue_gilded_chest")),
GREEN(cobblemonResource("green_gilded_chest")),
PINK(cobblemonResource("pink_gilded_chest")),
WHITE(cobblemonResource("white_gilded_chest")),
BLACK(cobblemonResource("black_gilded_chest")),
YELLOW(cobblemonResource("yellow_gilded_chest")),
FAKE(cobblemonResource("gilded_chest"))
}
@Deprecated("Deprecated in Java")
override fun canPathfindThrough(state: BlockState?, world: BlockView?, pos: BlockPos?, type: NavigationType?): Boolean {
return false
}
}
@@ -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.block.chest
import com.cobblemon.mod.common.api.scheduling.SchedulingTracker
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
import net.minecraft.entity.Entity
class GildedState : PoseableEntityState<Entity>() {
override fun getEntity() = null
init {
setPose("CLOSED")
}
override fun updatePartialTicks(partialTicks: Float) {
this.currentPartialTicks += partialTicks
}
override val schedulingTracker = SchedulingTracker()
}
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block.entity
import com.cobblemon.mod.common.CobblemonBlockEntities
import net.minecraft.block.BlockState
import net.minecraft.block.entity.BlockEntity
import net.minecraft.block.entity.BlockEntityTicker
import net.minecraft.util.math.BlockPos
class DyniteOreBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(CobblemonBlockEntities.DYNITE_ORE, pos, state) {
companion object {
internal val TICKER = BlockEntityTicker<DyniteOreBlockEntity> { world, pos, state, blockEntity ->
if (world.isClient) return@BlockEntityTicker
// idk if i'll actually need this but i already made it
}
}
}
@@ -1,149 +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.block.entity
import com.cobblemon.mod.common.CobblemonBlockEntities
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.block.chest.GildedChestBlock.Type
import com.cobblemon.mod.common.block.chest.GildedState
import net.minecraft.block.BlockState
import net.minecraft.block.entity.BlockEntityType
import net.minecraft.block.entity.LootableContainerBlockEntity
import net.minecraft.block.entity.ViewerCountManager
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.inventory.DoubleInventory
import net.minecraft.inventory.Inventories
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NbtCompound
import net.minecraft.screen.GenericContainerScreenHandler
import net.minecraft.sound.SoundCategory
import net.minecraft.state.property.Properties
import net.minecraft.text.Text
import net.minecraft.util.collection.DefaultedList
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
class GildedChestBlockEntity(pos: BlockPos, state: BlockState, val type: Type = Type.RED) : LootableContainerBlockEntity(CobblemonBlockEntities.GILDED_CHEST, pos, state) {
var inventoryContents: DefaultedList<ItemStack> = DefaultedList.ofSize(NUM_SLOTS, ItemStack.EMPTY)
val poseableState: GildedState = GildedState()
private val stateManager: ViewerCountManager = object : ViewerCountManager() {
override fun onContainerOpen(world: World, pos: BlockPos, state: BlockState) {
playSound(world, pos, state, CobblemonSounds.GILDED_CHEST_OPEN)
}
override fun onContainerClose(world: World, pos: BlockPos, state: BlockState) {
playSound(world, pos, state, CobblemonSounds.GILDED_CHEST_CLOSE)
}
override fun onViewerCountUpdate(
world: World,
pos: BlockPos,
state: BlockState,
oldViewerCount: Int,
newViewerCount: Int
) {
this@GildedChestBlockEntity.onViewerCountUpdate(world, pos, state, oldViewerCount, newViewerCount)
}
override fun isPlayerViewing(player: PlayerEntity): Boolean {
if (player.currentScreenHandler is GenericContainerScreenHandler) {
val inventory = (player.currentScreenHandler as GenericContainerScreenHandler).inventory
return inventory === this@GildedChestBlockEntity || inventory is DoubleInventory && inventory.isPart(
this@GildedChestBlockEntity
)
}
return false
}
}
override fun getType(): BlockEntityType<*> = CobblemonBlockEntities.GILDED_CHEST
override fun size() = NUM_SLOTS
override fun getContainerName() = Text.translatable("block.cobblemon.gilded_chest")
override fun createScreenHandler(syncId: Int, playerInventory: PlayerInventory?) =
GenericContainerScreenHandler.createGeneric9x3(syncId, playerInventory, this);
override fun onOpen(player: PlayerEntity) {
if (!this.removed && !player.isSpectator && type != Type.FAKE) {
stateManager.openContainer(player, this.getWorld(), this.getPos(), this.cachedState)
}
}
override fun onClose(player: PlayerEntity) {
if (!this.removed && !player.isSpectator) {
stateManager.closeContainer(player, this.getWorld(), this.getPos(), this.cachedState)
}
}
override fun getInvStackList(): DefaultedList<ItemStack> = inventoryContents
override fun setInvStackList(list: DefaultedList<ItemStack>) {
inventoryContents = list
}
companion object {
val NUM_SLOTS = 27
fun playSound(world: World, pos: BlockPos, state: BlockState, sound: net.minecraft.sound.SoundEvent) {
var d = pos.x.toDouble() + 0.5
val e = pos.y.toDouble() + 0.5
var f = pos.z.toDouble() + 0.5
val direction = state.get(Properties.HORIZONTAL_FACING)
d += direction.offsetX.toDouble() * 0.5
f += direction.offsetZ.toDouble() * 0.5
world.playSound(
null,
d,
e,
f,
sound,
SoundCategory.BLOCKS,
0.5f,
world.random.nextFloat() * 0.1f + 0.9f
)
}
}
override fun onSyncedBlockEvent(type: Int, data: Int): Boolean {
if (type == 1) {
val isNowOpen = data > 0
val wasOpen = poseableState.currentPose == "OPEN"
val model = poseableState.currentModel ?: return true
if (isNowOpen && !wasOpen) {
model.moveToPose(null, poseableState, model.getPose("OPEN")!!)
} else if (!isNowOpen && wasOpen) {
model.moveToPose(null, poseableState, model.getPose("CLOSED")!!)
}
return true
}
return super.onSyncedBlockEvent(type, data)
}
fun onViewerCountUpdate(world: World, pos: BlockPos, state: BlockState, oldViewerCount: Int, newViewerCount: Int) {
val block = state.block
world.addSyncedBlockEvent(pos, block, 1, newViewerCount)
}
override fun writeNbt(nbt: NbtCompound?) {
super.writeNbt(nbt)
if (!serializeLootTable(nbt)) {
Inventories.writeNbt(nbt, inventoryContents)
}
}
override fun readNbt(nbt: NbtCompound?) {
super.readNbt(nbt)
inventoryContents= DefaultedList.ofSize(
size(), ItemStack.EMPTY
)
if (!deserializeLootTable(nbt)) {
Inventories.readNbt(nbt, inventoryContents)
}
}
}
@@ -128,7 +128,7 @@ class RestorationTankBlockEntity(
val canUtilize = stack?.let { NaturalMaterials.isNaturalMaterial(it) } == true
&& structure.organicMaterialInside < FossilMultiblockStructure.MATERIAL_TO_START
&& structure.createdPokemon == null
val returnItem = NaturalMaterials.getReturnItem(stack!!) ?: return canUtilize
val returnItem = NaturalMaterials.getReturnItem(stack!!) ?: return false
if(canUtilize) {
// See if there's room
for (i in items.indices ) {
@@ -328,8 +328,8 @@ class FossilMultiblockStructure (
tankBaseEntity.masterBlockPos = null
tankTopEntity.masterBlockPos = null
// Drop fossils from machine as long as the machine is not started or near completion
if (this.timeRemaining == -1 || this.timeRemaining >= 20) {
// Drop fossils from machine as long as the machine is not running
if (this.timeRemaining == TIME_TO_TAKE || this.timeRemaining == -1) {
this.fossilInventory.forEach {
val stack = ItemStack(it.item, 1)
ItemScatterer.spawn(world, pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble(), stack)
@@ -25,15 +25,15 @@ import com.cobblemon.mod.common.client.particle.BedrockParticleEffectRepository
import com.cobblemon.mod.common.client.render.block.BerryBlockRenderer
import com.cobblemon.mod.common.client.render.block.FossilAnalyzerRenderer
import com.cobblemon.mod.common.client.render.block.RestorationTankRenderer
import com.cobblemon.mod.common.client.render.block.GildedChestBlockRenderer
import com.cobblemon.mod.common.client.render.block.HealingMachineRenderer
import com.cobblemon.mod.common.client.render.boat.CobblemonBoatRenderer
import com.cobblemon.mod.common.client.render.entity.PokeBobberEntityRenderer
import com.cobblemon.mod.common.client.render.entity.FallingStarRenderer
import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRendererRegistry
import com.cobblemon.mod.common.client.render.item.PokemonItemRenderer
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer
import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animation.BedrockAnimationRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.BerryModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.BlockEntityModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokeBallModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
import com.cobblemon.mod.common.client.render.pokeball.PokeBallRenderer
@@ -164,7 +164,6 @@ object CobblemonClient {
this.implementation.registerBlockRenderType(
RenderLayer.getCutout(),
CobblemonBlocks.GILDED_CHEST,
CobblemonBlocks.FOSSIL_ANALYZER,
CobblemonBlocks.APRICORN_DOOR,
CobblemonBlocks.APRICORN_TRAPDOOR,
@@ -218,7 +217,6 @@ object CobblemonClient {
CobblemonBlocks.MEDIUM_BUDDING_SKY_TUMBLESTONE,
CobblemonBlocks.LARGE_BUDDING_SKY_TUMBLESTONE,
CobblemonBlocks.SKY_TUMBLESTONE_CLUSTER,
CobblemonBlocks.GIMMIGHOUL_CHEST
)
this.createBoatModelLayers()
@@ -248,7 +246,6 @@ object CobblemonClient {
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.HANGING_SIGN, ::HangingSignBlockEntityRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.FOSSIL_ANALYZER, ::FossilAnalyzerRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.RESTORATION_TANK, ::RestorationTankRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.GILDED_CHEST, ::GildedChestBlockRenderer)
}
private fun registerEntityRenderers() {
@@ -260,6 +257,10 @@ object CobblemonClient {
this.implementation.registerEntityRenderer(CobblemonEntities.BOAT) { ctx -> CobblemonBoatRenderer(ctx, false) }
LOGGER.info("Registering Boat with Chest renderer")
this.implementation.registerEntityRenderer(CobblemonEntities.CHEST_BOAT) { ctx -> CobblemonBoatRenderer(ctx, true) }
LOGGER.info("Registering Falling Star renderer")
this.implementation.registerEntityRenderer(CobblemonEntities.FALLING_STAR_ENTITY) { ctx -> FallingStarRenderer(ctx) }
LOGGER.info("Registering PokeRod Bobber renderer")
this.implementation.registerEntityRenderer(CobblemonEntities.POKE_BOBBER) { ctx -> PokeBobberEntityRenderer(ctx) }
}
fun reloadCodedAssets(resourceManager: ResourceManager) {
@@ -267,13 +268,12 @@ object CobblemonClient {
BedrockParticleEffectRepository.loadEffects(resourceManager)
BedrockAnimationRepository.loadAnimations(
resourceManager = resourceManager,
directories = PokemonModelRepository.animationDirectories + PokeBallModelRepository.animationDirectories + FossilModelRepository.animationDirectories + BlockEntityModelRepository.animationDirectories
directories = PokemonModelRepository.animationDirectories + PokeBallModelRepository.animationDirectories + FossilModelRepository.animationDirectories
)
PokemonModelRepository.reload(resourceManager)
PokeBallModelRepository.reload(resourceManager)
BerryModelRepository.reload(resourceManager)
FossilModelRepository.reload(resourceManager)
BlockEntityModelRepository.reload(resourceManager)
MiscModelRepository.reload(resourceManager)
LOGGER.info("Loaded assets")
}
@@ -14,7 +14,6 @@ import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.battle.SingleActionRequest
import com.cobblemon.mod.common.client.gui.battle.BattleGUI
import com.cobblemon.mod.common.client.gui.battle.widgets.BattleOptionTile
import com.cobblemon.mod.common.net.messages.server.battle.FleeBattlePacket
import com.cobblemon.mod.common.util.battleLang
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.DrawContext
@@ -22,6 +21,7 @@ import net.minecraft.client.gui.Selectable
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder
import net.minecraft.client.sound.PositionedSoundInstance
import net.minecraft.client.sound.SoundManager
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.text.MutableText
import net.minecraft.util.Identifier
class BattleGeneralActionSelection(
@@ -61,8 +61,9 @@ class BattleGeneralActionSelection(
}
addOption(rank++, battleLang("ui.run"), BattleGUI.runResource) {
CobblemonClient.battle?.minimised = true
MinecraftClient.getInstance().player?.sendMessage(battleLang("run_prompt"), false)
playDownSound(MinecraftClient.getInstance().soundManager)
FleeBattlePacket(battle.battleId).sendToServer()
}
}
}
@@ -46,7 +46,7 @@ import net.minecraft.text.Text
* @author Qu
* @since 2022-06-18
*/
class StarterSelectionScreen(private val categories: List<RenderableStarterCategory>): Screen("cobblemon.ui.starter.title".asTranslated()) {
class StarterSelectionScreen private constructor(): Screen("cobblemon.ui.starter.title".asTranslated()) {
companion object {
// Size of UI at scale 1
@@ -63,14 +63,22 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
private val doubleTypeBackground = cobblemonResource("textures/gui/starterselection/starterselection_type_slot2.png")
}
private var currentSelection = 0
private lateinit var currentCategory: RenderableStarterCategory
private lateinit var modelWidget: ModelWidget
private lateinit var currentPokemon: RenderablePokemon
private lateinit var typeWidget: TypeWidget
private lateinit var starterRoundaboutCenter: StarterRoundabout
private lateinit var starterRoundaboutLeft: StarterRoundabout
private lateinit var starterRoundaboutRight: StarterRoundabout
lateinit var categories: List<RenderableStarterCategory>
lateinit var currentCategory: RenderableStarterCategory
lateinit var modelWidget: ModelWidget
lateinit var currentPokemon: RenderablePokemon
var currentSelection = 0
lateinit var rightButton: ArrowButton
lateinit var leftButton: ArrowButton
lateinit var typeWidget: TypeWidget
lateinit var selectionButton: SelectionButton
lateinit var starterRoundaboutCenter: StarterRoundabout
lateinit var starterRoundaboutLeft: StarterRoundabout
lateinit var starterRoundaboutRight: StarterRoundabout
constructor(categories: List<RenderableStarterCategory>) : this() {
this.categories = categories
}
override fun init() {
super.init()
@@ -94,7 +102,7 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
)
)
val rightButton = ArrowButton(
rightButton = ArrowButton(
pX = x + 183, pY = y + 151,
pWidth = 9, pHeight = 14,
right = true
@@ -102,7 +110,7 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
right()
}
val leftButton = ArrowButton(
leftButton = ArrowButton(
pX = x + 72, pY = y + 151,
pWidth = 9, pHeight = 14,
right = false
@@ -129,7 +137,7 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
addDrawableChild(modelWidget)
val selectionButton = SelectionButton(
selectionButton = SelectionButton(
pX = x + 106, pY = y + 124,
pWidth = SelectionButton.BUTTON_WIDTH, pHeight = SelectionButton.BUTTON_HEIGHT
) {
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common.client.gui.summary
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.moves.Move
@@ -60,7 +59,7 @@ import net.minecraft.text.Text
*
* @param selection The index the [party] will have as the base [selectedPokemon].
*/
class Summary private constructor(party: Collection<Pokemon?>, private val editable: Boolean, private val selection: Int): Screen(Text.translatable("cobblemon.ui.summary.title")), Schedulable {
class Summary private constructor(party: Collection<Pokemon?>, private val editable: Boolean, selection: Int): Screen(Text.translatable("cobblemon.ui.summary.title")), Schedulable {
companion object {
const val BASE_WIDTH = 331
@@ -107,27 +106,24 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
override val schedulingTracker = SchedulingTracker()
internal lateinit var selectedPokemon: Pokemon
internal var selectedPokemon: Pokemon
private lateinit var mainScreen: ClickableWidget
lateinit var sideScreen: Element
private lateinit var modelWidget: ModelWidget
private lateinit var nicknameEntryWidget: NicknameEntryWidget
lateinit var modelWidget: ModelWidget
lateinit var nicknameEntryWidget: NicknameEntryWidget
private val summaryTabs = mutableListOf<SummaryTab>()
private var mainScreenIndex = INFO
var sideScreenIndex = PARTY
private val party = ArrayList(party)
/**
* Initializes the Summary Screen
*/
override fun init() {
super.init()
init {
if (this.party.isEmpty()) {
throw IllegalArgumentException("Summary UI cannot display zero Pokemon")
}
if (this.party.size > 6) {
throw IllegalArgumentException("Summary UI cannot display more than six Pokemon")
}
val idealSelected = this.party[selection]
if (idealSelected == null) {
this.selectedPokemon = this.party.first { it != null }!!
@@ -135,6 +131,14 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
this.selectedPokemon = idealSelected
}
this.listenToMoveSet()
}
/**
* Initializes the Summary Screen
*/
public override fun init() {
clearChildren()
super.init()
val x = (width - BASE_WIDTH) / 2
val y = (height - BASE_HEIGHT) / 2
@@ -241,7 +245,6 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
rotationY = 325F,
offsetY = -10.0
)
addDrawable(this.modelWidget)
}
fun swapPartySlot(sourceIndex: Int, targetIndex: Int) {
@@ -278,12 +281,8 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
listenToMoveSet()
displayMainScreen(mainScreenIndex)
children().find { it is EvolutionSelectScreen }?.let(this::remove)
if (this::modelWidget.isInitialized) {
this.modelWidget.pokemon = selectedPokemon.asRenderablePokemon()
}
if (this::nicknameEntryWidget.isInitialized) {
this.nicknameEntryWidget.setSelectedPokemon(selectedPokemon)
}
modelWidget.pokemon = selectedPokemon.asRenderablePokemon()
nicknameEntryWidget.setSelectedPokemon(selectedPokemon)
}
private var moveSetSubscription: ObservableSubscription<MoveSet>? = null
@@ -310,7 +309,7 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
*/
private fun displayMainScreen(screen: Int) {
// Get stat tab index if currently displaying stat screen
val subIndex = if (mainScreenIndex == STATS && mainScreen is StatWidget) (mainScreen as StatWidget).statTabIndex else 0
var subIndex = if (mainScreenIndex == STATS && mainScreen is StatWidget) (mainScreen as StatWidget).statTabIndex else 0
mainScreenIndex = screen
if (::mainScreen.isInitialized) remove(mainScreen)
@@ -409,10 +408,10 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
}
}
override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
//this.renderBackground(context)
override fun render(context: DrawContext, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
renderBackground(context)
schedulingTracker.update(delta / 20F)
schedulingTracker.update(pPartialTicks / 20F)
val x = (width - BASE_WIDTH) / 2
val y = (height - BASE_HEIGHT) / 2
@@ -428,7 +427,7 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
height = PORTRAIT_SIZE
)
//modelWidget.render(context, pMouseX, pMouseY, pPartialTicks)
modelWidget.render(context, pMouseX, pMouseY, pPartialTicks)
// Render Base Resource
blitk(
@@ -577,29 +576,29 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
)
// Render all added Widgets
super.render(context, mouseX, mouseY, delta)
super.render(context, pMouseX, pMouseY, pPartialTicks)
// Render Item Tooltip
if (!heldItem.isEmpty) {
val itemHovered = mouseX.toFloat() in (itemX.toFloat()..(itemX.toFloat() + 16)) && mouseY.toFloat() in (itemY.toFloat()..(itemY.toFloat() + 16))
if (itemHovered) context.drawItemTooltip(MinecraftClient.getInstance().textRenderer, heldItem, mouseX, mouseY)
val itemHovered = pMouseX.toFloat() in (itemX.toFloat()..(itemX.toFloat() + 16)) && pMouseY.toFloat() in (itemY.toFloat()..(itemY.toFloat() + 16))
if (itemHovered) context.drawItemTooltip(MinecraftClient.getInstance().textRenderer, heldItem, pMouseX, pMouseY)
}
}
/**
* Whether this Screen should pause the Game in SinglePlayer
*/
override fun shouldPause(): Boolean = false
override fun shouldPause(): Boolean {
return false
}
override fun mouseScrolled(mouseX: Double, mouseY: Double, amount: Double): Boolean {
return children().any { it.mouseScrolled(mouseX, mouseY, amount) }
}
/*
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
return children().any { it.mouseClicked(mouseX, mouseY, button) }
}
*/
override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, deltaX: Double, deltaY: Double): Boolean {
if (sideScreenIndex == MOVE_SWAP || sideScreenIndex == EVOLVE) sideScreen.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)
@@ -607,17 +606,17 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
}
override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
if ((keyCode == InputUtil.GLFW_KEY_ENTER || keyCode == InputUtil.GLFW_KEY_KP_ENTER)
&& this::nicknameEntryWidget.isInitialized
&& this.nicknameEntryWidget.isFocused
) {
this.focused = null
if ((keyCode == InputUtil.GLFW_KEY_ENTER || keyCode == InputUtil.GLFW_KEY_KP_ENTER) && nicknameEntryWidget.isFocused) { // Enter pressed
nicknameEntryWidget.isFocused = false
}
return super.keyPressed(keyCode, scanCode, modifiers)
return nicknameEntryWidget.keyPressed(keyCode, scanCode, modifiers) || super.keyPressed(keyCode, scanCode, modifiers)
}
override fun charTyped(chr: Char, modifiers: Int): Boolean {
return nicknameEntryWidget.charTyped(chr, modifiers) || super.charTyped(chr, modifiers)
}
fun playSound(soundEvent: SoundEvent) {
MinecraftClient.getInstance().soundManager.play(PositionedSoundInstance.master(soundEvent, 1.0F))
}
}
@@ -19,7 +19,6 @@ import net.minecraft.client.gui.widget.ButtonWidget
import net.minecraft.client.sound.PositionedSoundInstance
import net.minecraft.client.sound.SoundManager
import net.minecraft.text.MutableText
import net.minecraft.text.Text
import net.minecraft.util.Identifier
class SummaryButton(
@@ -28,7 +27,7 @@ class SummaryButton(
val buttonWidth: Number,
val buttonHeight: Number,
val clickAction: PressAction,
private val text: MutableText = Text.empty(),
private val text: MutableText? = null,
private val resource: Identifier,
private val activeResource: Identifier? = null,
private val renderRequirement: ((button: SummaryButton) -> Boolean) = { true },
@@ -69,16 +68,18 @@ class SummaryButton(
)
// Render Text
drawScaledText(
context = context,
font = if (largeText) CobblemonResources.DEFAULT_LARGE else null,
text = if (boldText) text.bold() else text,
x = buttonX + (buttonWidth.toFloat() / 2),
y = buttonY + (buttonHeight.toFloat() / 2) - ((TEXT_HEIGHT / 2) * textScale),
scale = textScale,
centered = true,
shadow = true
)
if (text != null) {
drawScaledText(
context = context,
font = if (largeText) CobblemonResources.DEFAULT_LARGE else null,
text = if (boldText) text.bold() else text,
x = buttonX + (buttonWidth.toFloat() / 2),
y = buttonY + (buttonHeight.toFloat() / 2) - ((TEXT_HEIGHT / 2) * textScale),
scale = textScale,
centered = true,
shadow = true
)
}
}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
@@ -1,110 +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.client.gui.summary.featurerenderers
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.pokemon.feature.IntSpeciesFeature
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.stats.StatWidget
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.client.gui.DrawContext
import net.minecraft.text.MutableText
import net.minecraft.util.Identifier
import net.minecraft.util.math.MathHelper
import net.minecraft.util.math.Vec3d
/**
* Renders an [IntSpeciesFeature] as a bar in the summary screen.
*
* @author Hiroku
* @since November 13th, 2023
*/
class BarSummarySpeciesFeatureRenderer(
override val name: String,
val displayName: MutableText,
val min: Int,
val max: Int,
val colour: Vec3d,
val underlay: Identifier,
val overlay: Identifier,
val pokemon: Pokemon
) : SummarySpeciesFeatureRenderer<IntSpeciesFeature> {
override fun render(drawContext: DrawContext, x: Float, y: Float, pokemon: Pokemon, feature: IntSpeciesFeature) {
val value = feature.value
val barRatio = (value - min) / (max - min).toFloat()
val barWidth = MathHelper.ceil(barRatio * 108)
blitk(
matrixStack = drawContext.matrices,
texture = underlay,
x = x,
y = y,
height = 28,
width = 124
)
val red = colour.x / 255F
val green = colour.y / 255F
val blue = colour.z / 255F
blitk(
matrixStack = drawContext.matrices,
texture = CobblemonResources.WHITE,
x = x + 8,
y = y + 16,
height = 10,
width = barWidth,
red = red,
green = green,
blue = blue
)
blitk(
matrixStack = drawContext.matrices,
texture = overlay,
x = x / StatWidget.SCALE,
y = (y + 16) / StatWidget.SCALE,
height = 20,
width = 248,
scale = StatWidget.SCALE
)
// Label
drawScaledText(
context = drawContext,
font = CobblemonResources.DEFAULT_LARGE,
text = displayName.bold(),
x = x + 62,
y = y + 2.5,
centered = true,
shadow = true
)
drawScaledText(
context = drawContext,
text = value.toString().text(),
x = x + 11,
y = y + 6,
scale = StatWidget.SCALE,
centered = true
)
drawScaledText(
context = drawContext,
text = "${MathHelper.floor(barRatio * 100)}%".text(),
x = x + 113,
y = y + 6,
scale = StatWidget.SCALE,
centered = true
)
}
}
@@ -1,32 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.gui.summary.featurerenderers
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeature
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.client.gui.DrawContext
/**
* A renderer for some kind of [SynchronizedSpeciesFeature] so that it will display
* in the summary screen of the Pokémon (under other stats).
*
* @author Hiroku
* @since November 13th, 2023
*/
interface SummarySpeciesFeatureRenderer<T : SynchronizedSpeciesFeature> {
/** The name of the feature (so we know where to look to find it in the [Pokemon]) */
val name: String
/** Draws it at a particular position. */
fun render(drawContext: DrawContext, x: Float, y: Float, pokemon: Pokemon, feature: T)
fun render(drawContext: DrawContext, x: Float, y: Float, pokemon: Pokemon): Boolean {
val feature = pokemon.getFeature<T>(name) ?: return false
render(drawContext, x, y, pokemon, feature)
return true
}
}
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.client.gui.summary.widgets
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
import com.cobblemon.mod.common.client.gui.summary.Summary
@@ -22,14 +23,15 @@ import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.text.Text
import net.minecraft.util.Identifier
import org.joml.Quaternionf
import org.joml.Vector3f
class PartySlotWidget(
pX: Number,
pY: Number,
private val pX: Number,
private val pY: Number,
private val partyWidget: PartyWidget,
private val summary: Summary,
private val pokemon: Pokemon?,
@@ -0,0 +1,20 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.gui.summary.widgets
import com.cobblemon.mod.common.util.cobblemonResource
class TypeDisplayWidget {
companion object {
private val TYPES_RESOURCE = cobblemonResource("textures/gui/types.png")
}
}
@@ -26,7 +26,9 @@ class InfoBlockWidget(
private val font: Identifier,
) : SoundlessWidget(pX, pY, blockWidth, blockHeight, Text.literal("InfoBlockWidget")) {
override fun renderButton(context: DrawContext, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
drawScaledText(
context = context,
font = font,
@@ -15,13 +15,14 @@ import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.widget.ButtonWidget
import net.minecraft.client.sound.PositionedSoundInstance
import net.minecraft.client.sound.SoundManager
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.text.Text
class ReorderMoveButton(
val pX: Int, val pY: Int,
private val isUp: Boolean,
onPress: PressAction
): ButtonWidget((pX - OFFSET_X).toInt(), (pY + (if (isUp) OFFSET_Y_UP else OFFSET_Y_DOWN)), (WIDTH * SCALE).toInt(), (HEIGHT * SCALE).toInt(), Text.empty(), onPress, DEFAULT_NARRATION_SUPPLIER) {
): ButtonWidget((pX - OFFSET_X).toInt(), (pY + (if (isUp) OFFSET_Y_UP else OFFSET_Y_DOWN)), (WIDTH * SCALE).toInt(), (HEIGHT * SCALE).toInt(), Text.literal(""), onPress, DEFAULT_NARRATION_SUPPLIER) {
companion object {
private const val WIDTH = 8
@@ -29,7 +29,7 @@ class SwapMoveButton(
var move: MoveTemplate,
var movesWidget: MovesWidget,
onPress: PressAction
): ButtonWidget((pX + OFFSET_X).toInt(), (pY + OFFSET_Y).toInt(), (WIDTH * SCALE).toInt(), (HEIGHT * SCALE).toInt(), Text.empty(), onPress, DEFAULT_NARRATION_SUPPLIER) {
): ButtonWidget((pX + OFFSET_X).toInt(), (pY + OFFSET_Y).toInt(), (WIDTH * SCALE).toInt(), (HEIGHT * SCALE).toInt(), Text.literal(""), onPress, DEFAULT_NARRATION_SUPPLIER) {
override fun mouseDragged(d: Double, e: Double, i: Int, f: Double, g: Double): Boolean {
return false
@@ -10,8 +10,6 @@ package com.cobblemon.mod.common.client.gui.summary.widgets.screens.stats
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.stats.Stat
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.text.bold
@@ -56,7 +54,7 @@ class StatWidget(
private const val WIDTH = 134
private const val HEIGHT = 148
const val SCALE = 0.5F
private const val SCALE = 0.5F
private const val WHITE = 0x00FFFFFF
private const val GREY = 0x00AAAAAA
@@ -66,7 +64,6 @@ class StatWidget(
private val statsBaseResource = cobblemonResource("textures/gui/summary/summary_stats_chart_base.png")
private val statsChartResource = cobblemonResource("textures/gui/summary/summary_stats_chart.png")
private val statsOtherBaseResource = cobblemonResource("textures/gui/summary/summary_stats_other_base.png")
private val statsOtherBarTemplate = cobblemonResource("textures/gui/summary/summary_stats_other_bar.png")
private val friendshipOverlayResource = cobblemonResource("textures/gui/summary/summary_stats_friendship_overlay.png")
private val tabMarkerResource = cobblemonResource("textures/gui/summary/summary_stats_tab_marker.png")
private val statIncreaseResource = cobblemonResource("textures/gui/summary/summary_stats_icon_increase.png")
@@ -87,10 +84,6 @@ class StatWidget(
}
var statTabIndex = tabIndex
val renderableFeatures = SpeciesFeatures
.getFeaturesFor(pokemon.species)
.filterIsInstance<SynchronizedSpeciesFeatureProvider<*>>()
.mapNotNull { it.getRenderer(pokemon) }
private fun drawTriangle(
colour: Vector3f,
@@ -185,74 +178,6 @@ class StatWidget(
// drawTriangle(colour, specialAttackPoint, centerPoint, hpPoint)
}
private fun drawFriendship(moduleX: Int, moduleY: Int, matrices: MatrixStack, context: DrawContext, friendship: Int) {
val barRatio = friendship / 255F
val barWidth = ceil(barRatio * 108)
blitk(
matrixStack = matrices,
texture = statsOtherBarTemplate,
x = moduleX,
y = moduleY,
height = 28,
width = 124
)
val red = 1
val green: Number = if (pokemon.friendship >= 160) 0.28 else 0.56
val blue: Number = if (pokemon.friendship >= 160) 0.4 else 0.64
blitk(
matrixStack = matrices,
texture = CobblemonResources.WHITE,
x = moduleX + 8,
y = moduleY + 18,
height = 8,
width = barWidth,
red = red,
green = green,
blue = blue
)
blitk(
matrixStack = matrices,
texture = friendshipOverlayResource,
x = moduleX / SCALE,
y = (moduleY + 16) / SCALE,
height = 20,
width = 248,
scale = SCALE
)
// Label
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = lang("ui.stats.friendship").bold(),
x = moduleX + 62,
y = moduleY + 2.5,
centered = true,
shadow = true
)
drawScaledText(
context = context,
text = friendship.toString().text(),
x = moduleX + 11,
y = moduleY + 6,
scale = SCALE,
centered = true
)
drawScaledText(
context = context,
text = "${floor(barRatio * 100)}%".text(),
x = moduleX + 113,
y = moduleY + 6,
scale = SCALE,
centered = true
)
}
override fun renderButton(context: DrawContext, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
val renderChart = statTabIndex != OTHER
@@ -403,28 +328,60 @@ class StatWidget(
renderModifiedStatIcon(matrices, nature.decreasedStat, false)
}
} else {
var drawY = y + 11
// Friendship
val friendshipBarWidthMax = 108
val friendshipRatio = pokemon.friendship / 255F
val friendshipBarWidth = ceil(friendshipRatio * friendshipBarWidthMax)
blitk(
matrixStack = matrices,
texture = CobblemonResources.WHITE,
x = x + 13,
y = y + 27,
height = 8,
width = friendshipBarWidth,
red = 0.92,
green = if (pokemon.friendship >= 160) 0.28 else 0.7,
blue = if (pokemon.friendship >= 160) 0.4 else 0.28
)
drawFriendship(x + 5, drawY, matrices, context, pokemon.friendship)
drawY += 30
blitk(
matrixStack = matrices,
texture = friendshipOverlayResource,
x = (x + 5) / SCALE,
y = (y + 26) / SCALE,
height = 20,
width = 248,
scale = SCALE
)
for (renderableFeature in renderableFeatures) {
val rendered = renderableFeature.render(
drawContext = context,
x = x + 5F,
y = drawY.toFloat(),
pokemon = pokemon
)
// Label
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = lang("ui.stats.friendship").bold(),
x = x + 67,
y = y + 12.5,
centered = true,
shadow = true
)
if (rendered) {
drawY += 30
}
}
// for (value in summaries) {
// drawBarModule(x + 5, drawY, matrices, context, value)
// }
drawScaledText(
context = context,
text = pokemon.friendship.toString().text(),
x = x + 16,
y = y + 16,
scale = SCALE,
centered = true
)
drawScaledText(
context = context,
text = "${floor(friendshipRatio * 100)}%".text(),
x = x + 118,
y = y + 16,
scale = SCALE,
centered = true
)
}
}
@@ -1,65 +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.client.render.block
import com.cobblemon.mod.common.block.entity.GildedChestBlockEntity
import com.cobblemon.mod.common.client.render.models.blockbench.repository.BlockEntityModelRepository
import net.minecraft.client.render.OverlayTexture
import net.minecraft.client.render.VertexConsumerProvider
import net.minecraft.client.render.block.entity.BlockEntityRenderer
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.state.property.Properties
import net.minecraft.util.math.RotationAxis
class GildedChestBlockRenderer(context: BlockEntityRendererFactory.Context) : BlockEntityRenderer<GildedChestBlockEntity> {
override fun render(
entity: GildedChestBlockEntity,
tickDelta: Float,
matrices: MatrixStack,
vertexConsumers: VertexConsumerProvider,
light: Int,
overlay: Int
) {
val aspects = emptySet<String>()
val state = entity.poseableState
state.updatePartialTicks(tickDelta)
val poserId = entity.type.poserId
val model = BlockEntityModelRepository.getPoser(poserId, aspects)
val texture = BlockEntityModelRepository.getTexture(poserId, aspects, state.animationSeconds)
val vertexConsumer = vertexConsumers.getBuffer(model.getLayer(texture))
model.bufferProvider = vertexConsumers
state.currentModel = model
matrices.push()
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(180f))
matrices.translate(-0.5, 0.0, 0.5)
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(entity.cachedState.get(Properties.HORIZONTAL_FACING).asRotation()))
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180f))
model.setupAnimStateful(
entity = null,
state = state,
headYaw = 0F,
headPitch = 0F,
limbSwing = 0F,
limbSwingAmount = 0F,
ageInTicks = state.animationSeconds * 20
)
model.render(matrices, vertexConsumer, light, overlay, 1.0f, 1.0f, 1.0f, 1.0f)
model.withLayerContext(vertexConsumers, state, BlockEntityModelRepository.getLayers(poserId, aspects)) {
model.render(matrices, vertexConsumer, light, OverlayTexture.DEFAULT_UV, 1F, 1F, 1F, 1F)
}
model.setDefault()
matrices.pop()
}
}
@@ -0,0 +1,21 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.entity
import com.cobblemon.mod.common.entity.fallingstar.FallingStarEntity
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.render.entity.EntityRenderer
import net.minecraft.client.render.entity.EntityRendererFactory
import net.minecraft.util.Identifier
class FallingStarRenderer(ctx: EntityRendererFactory.Context?) : EntityRenderer<FallingStarEntity>(ctx) {
override fun getTexture(entity: FallingStarEntity): Identifier {
return cobblemonResource("textures/red")
}
}
@@ -0,0 +1,136 @@
/*
* 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.client.render.entity
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.util.cobblemonResource
import net.fabricmc.api.EnvType
import net.fabricmc.api.Environment
import net.minecraft.client.MinecraftClient
import net.minecraft.client.render.OverlayTexture
import net.minecraft.client.render.RenderLayer
import net.minecraft.client.render.VertexConsumer
import net.minecraft.client.render.VertexConsumerProvider
import net.minecraft.client.render.entity.EntityRenderer
import net.minecraft.client.render.entity.EntityRendererFactory
import net.minecraft.client.render.entity.FishingBobberEntityRenderer
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.entity.projectile.FishingBobberEntity
import net.minecraft.item.Items
import net.minecraft.util.Arm
import net.minecraft.util.Identifier
import net.minecraft.util.math.MathHelper
import net.minecraft.util.math.RotationAxis
import org.joml.Matrix3f
import org.joml.Matrix4f
/*
* Decompiled with CFR 0.2.0 (FabricMC d28b102d).
*/
@Environment(value = EnvType.CLIENT)
class PokeBobberEntityRenderer(context: EntityRendererFactory.Context?) : EntityRenderer<FishingBobberEntity>(context) {
override fun render(fishingBobberEntity: FishingBobberEntity, f: Float, g: Float, matrixStack: MatrixStack, vertexConsumerProvider: VertexConsumerProvider, i: Int) {
var s: Double
val r: Float
val q: Double
val p: Double
val o: Double
val playerEntity = fishingBobberEntity.playerOwner ?: return
matrixStack.push()
matrixStack.push()
matrixStack.scale(0.5f, 0.5f, 0.5f)
matrixStack.multiply(dispatcher.rotation)
matrixStack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180.0f))
val entry = matrixStack.peek()
val matrix4f = entry.positionMatrix
val matrix3f = entry.normalMatrix
val vertexConsumer = vertexConsumerProvider.getBuffer(PokeBobberEntityRenderer.Companion.LAYER)
PokeBobberEntityRenderer.Companion.vertex(vertexConsumer, matrix4f, matrix3f, i, 0.0f, 0, 0, 1)
PokeBobberEntityRenderer.Companion.vertex(vertexConsumer, matrix4f, matrix3f, i, 1.0f, 0, 1, 1)
PokeBobberEntityRenderer.Companion.vertex(vertexConsumer, matrix4f, matrix3f, i, 1.0f, 1, 1, 0)
PokeBobberEntityRenderer.Companion.vertex(vertexConsumer, matrix4f, matrix3f, i, 0.0f, 1, 0, 0)
matrixStack.pop()
var j = if (playerEntity.mainArm == Arm.RIGHT) 1 else -1
val itemStack = playerEntity.mainHandStack
if (!itemStack.isOf(CobblemonItems.POKEROD)) {
j = -j
}
val h = playerEntity.getHandSwingProgress(g)
val k = MathHelper.sin(MathHelper.sqrt(h) * Math.PI.toFloat())
val l = MathHelper.lerp(g, playerEntity.prevBodyYaw, playerEntity.bodyYaw) * (Math.PI.toFloat() / 180)
val d = MathHelper.sin(l).toDouble()
val e = MathHelper.cos(l).toDouble()
val m = j.toDouble() * 0.35
val n = 0.8
if (dispatcher.gameOptions != null && !dispatcher.gameOptions.perspective.isFirstPerson || playerEntity !== MinecraftClient.getInstance().player) {
o = MathHelper.lerp(g.toDouble(), playerEntity.prevX, playerEntity.x) - e * m - d * 0.8
p = playerEntity.prevY + playerEntity.standingEyeHeight.toDouble() + (playerEntity.y - playerEntity.prevY) * g.toDouble() - 0.45
q = MathHelper.lerp(g.toDouble(), playerEntity.prevZ, playerEntity.z) - d * m + e * 0.8
r = if (playerEntity.isInSneakingPose) -0.1875f else 0.0f
} else {
s = 960.0 / dispatcher.gameOptions.fov.value.toDouble()
var vec3d = dispatcher.camera.projection.getPosition(j.toFloat() * 0.525f, -0.1f)
vec3d = vec3d.multiply(s)
vec3d = vec3d.rotateY(k * 0.5f)
vec3d = vec3d.rotateX(-k * 0.7f)
o = MathHelper.lerp(g.toDouble(), playerEntity.prevX, playerEntity.getX()) + vec3d.x
p = MathHelper.lerp(g.toDouble(), playerEntity.prevY, playerEntity.getY()) + vec3d.y
q = MathHelper.lerp(g.toDouble(), playerEntity.prevZ, playerEntity.getZ()) + vec3d.z
r = playerEntity.getStandingEyeHeight()
}
s = MathHelper.lerp(g.toDouble(), fishingBobberEntity.prevX, fishingBobberEntity.x)
val t = MathHelper.lerp(g.toDouble(), fishingBobberEntity.prevY, fishingBobberEntity.y) + 0.25
val u = MathHelper.lerp(g.toDouble(), fishingBobberEntity.prevZ, fishingBobberEntity.z)
val v = (o - s).toFloat()
val w = (p - t).toFloat() + r
val x = (q - u).toFloat()
val vertexConsumer2 = vertexConsumerProvider.getBuffer(RenderLayer.getLineStrip())
val entry2 = matrixStack.peek()
val y = 16
for (z in 0..16) {
renderFishingLine(v, w, x, vertexConsumer2, entry2, percentage(z, 16), percentage(z + 1, 16))
}
matrixStack.pop()
super.render(fishingBobberEntity, f, g, matrixStack, vertexConsumerProvider, i)
}
override fun getTexture(fishingBobberEntity: FishingBobberEntity): Identifier {
return TEXTURE
}
companion object {
private val TEXTURE = cobblemonResource("textures/item/fishing/pokeball_bobber.png")
private val LAYER = RenderLayer.getEntityCutout(TEXTURE)
private const val field_33632 = 960.0
@JvmStatic
private fun percentage(value: Int, max: Int): Float {
return value.toFloat() / max.toFloat()
}
private fun vertex(buffer: VertexConsumer, matrix: Matrix4f, normalMatrix: Matrix3f, light: Int, x: Float, y: Int, u: Int, v: Int) {
buffer.vertex(matrix, x - 0.5f, y.toFloat() - 0.5f, 0.0f).color(255, 255, 255, 255).texture(u.toFloat(), v.toFloat()).overlay(OverlayTexture.DEFAULT_UV).light(light).normal(normalMatrix, 0.0f, 1.0f, 0.0f).next()
}
@JvmStatic
private fun renderFishingLine(x: Float, y: Float, z: Float, buffer: VertexConsumer, matrices: MatrixStack.Entry, segmentStart: Float, segmentEnd: Float) {
val f = x * segmentStart
val g = y * (segmentStart * segmentStart + segmentStart) * 0.5f + 0.25f
val h = z * segmentStart
var i = x * segmentEnd - f
var j = y * (segmentEnd * segmentEnd + segmentEnd) * 0.5f + 0.25f - g
var k = z * segmentEnd - h
val l = MathHelper.sqrt(i * i + j * j + k * k)
i /= l
j /= l
k /= l
buffer.vertex(matrices.positionMatrix, f, g, h).color(0, 0, 0, 255).normal(matrices.normalMatrix, i, j, k).next()
}
}
}
@@ -0,0 +1,40 @@
/*
* 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.client.render.item
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.item.PokerodItem
import net.minecraft.client.item.ClampedModelPredicateProvider
import net.minecraft.client.item.ModelPredicateProvider
import net.minecraft.client.item.ModelPredicateProviderRegistry
import net.minecraft.client.world.ClientWorld
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.util.Identifier
object CobblemonModelPredicateRegistry {
fun registerPredicates() {
ModelPredicateProviderRegistry.register(CobblemonItems.POKEROD, Identifier("cast"), ClampedModelPredicateProvider { stack: ItemStack, world: ClientWorld?, entity: LivingEntity?, seed: Int ->
if (entity == null) {
return@ClampedModelPredicateProvider 0.0f
} else {
val bl = entity.mainHandStack == stack
var bl2 = entity.offHandStack == stack
if (entity.mainHandStack.item is PokerodItem) {
bl2 = false
}
return@ClampedModelPredicateProvider if ((bl || bl2) && entity is PlayerEntity && (entity.fishHook != null)) 1.0f else 0.0f
}
})
}
}
@@ -753,7 +753,7 @@ abstract class PoseableEntityModel<T : Entity>(
}
} else if (transition != null) {
val animation = transition(previousPose, desirablePose)
val primaryAnimation = if (animation is PrimaryAnimation) animation else PrimaryAnimation(animation, curve = { 1F })
val primaryAnimation = PrimaryAnimation(animation, curve = { 1F })
state.addPrimaryAnimation(primaryAnimation)
afterOnClient(seconds = primaryAnimation.duration) {
state.setPose(desirablePose.poseName)
@@ -1,44 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.blockentity
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityModel
import com.cobblemon.mod.common.client.render.models.blockbench.animation.StatelessAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.ModelFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Bone
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.ModelPart
import net.minecraft.entity.Entity
class BlockEntityModel(val root: Bone) : PoseableEntityModel<Entity>() {
val boneName: String = root.children.entries.first().key
override val rootPart = (root as ModelPart).registerChildWithAllChildren(boneName)
override val isForLivingEntityRenderer = false
var idleAnimations: Array<StatelessAnimation<Entity, out ModelFrame>> = emptyArray()
var maxScale = 1F
var yTranslation = 0F
override fun registerPoses() {
val closedPose = registerPose<ModelFrame>(poseName = "CLOSED", poseType = PoseType.NONE)
val openPose = registerPose(
poseType = PoseType.OPEN,
idleAnimations = arrayOf(bedrock("gilded_chest", "open"))
)
closedPose.transitions[openPose.poseName] = { _, _ ->
bedrockStateful("gilded_chest", "opening").andThen { _, state -> state.setPose(openPose.poseName) }
}
openPose.transitions[closedPose.poseName] = { _, _ ->
bedrockStateful("gilded_chest", "closing").andThen { _, state -> state.setPose(closedPose.poseName) }
}
}
override fun getState(entity: Entity) = throw NotImplementedError("This is not supported for the gilded chest")
}
@@ -19,7 +19,7 @@ import net.minecraft.entity.Entity
class FossilModel(root: Bone) : PoseableEntityModel<Entity>() {
override val isForLivingEntityRenderer = false
//TODO: Find a better way to fetch this bone name - Update the BlockEntityModel too when you figure it out
//TODO: Find a better way to fetch this bone name
val boneName: String = root.children.entries.first().key
override val rootPart = (root as ModelPart).registerChildWithAllChildren(boneName)
// Represents a very rough middle of the model
@@ -1,70 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen9
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BimanualSwingAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.ModelPart
import net.minecraft.util.math.Vec3d
class GholdengoModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame, BipedFrame, BimanualFrame {
override val rootPart = root.registerChildWithAllChildren("gholdengo")
override val head = getPart("head")
override val leftArm = getPart("arm_left")
override val rightArm = getPart("arm_right")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
override val portraitScale = 2.6F
override val portraitTranslation = Vec3d(-0.3, 1.4, 0.0)
override val profileScale = 0.65F
override val profileTranslation = Vec3d(0.0, 0.76, 0.0)
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
override fun registerPoses() {
val blink = quirk { bedrockStateful("gholdengo", "blink") }
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("gholdengo", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("gholdengo", "ground_idle"),
BipedWalkAnimation(this, periodMultiplier = 0.6F, amplitudeMultiplier = 0.9F),
BimanualSwingAnimation(this, swingPeriodMultiplier = 0.6F, amplitudeMultiplier = 0.9F)
//bedrock("gholdengo", "ground_walk")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PoseableEntityState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("gholdengo", "faint") else null
}
@@ -1,97 +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.client.render.models.blockbench.pokemon.gen9
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.util.asExpressionLike
import net.minecraft.client.model.ModelPart
import net.minecraft.util.math.Vec3d
class GimmighoulChestModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame, BipedFrame, BimanualFrame {
override val rootPart = root.registerChildWithAllChildren("gimmighoul_chest")
override val head = getPart("head")
override val leftArm = getPart("arm_left")
override val rightArm = getPart("arm_right")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
override val portraitScale = 2.0F
override val portraitTranslation = Vec3d(0.3, -0.7, 0.0)
override val profileScale = 0.65F
override val profileTranslation = Vec3d(0.0, 0.76, 0.0)
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
lateinit var closed: PokemonPose
lateinit var battle: PokemonPose
override fun registerPoses() {
val blink = quirk { bedrockStateful("gimmighoul_chest", "blink") }
animations["cry"] = "q.bedrock_stateful('gimmighoul_chest', 'cry')".asExpressionLike()
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
quirks = arrayOf(blink),
condition = { it.ownerUuid != null && !it.isBattling },
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("gimmighoul_chest", "ground_idle")
)
)
closed = registerPose(
poseName = "closed",
poseTypes = PoseType.STATIONARY_POSES,
quirks = arrayOf(blink),
condition = { it.ownerUuid == null && !it.isBattling },
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("gimmighoul_chest", "mimic")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("gimmighoul_chest", "ground_walk")
//bedrock("gimmighoul_chest", "ground_walk")
)
)
battle = registerPose(
poseName = "battle",
poseTypes = PoseType.STATIONARY_POSES,
quirks = arrayOf(blink),
condition = { it.isBattling },
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("gimmighoul_chest", "battle_idle"),
)
)
closed.transitions[battle.poseName] = { _, _ ->
bedrockStateful("gimmighoul_chest", "surprise").andThen { _, state -> state.setPose(battle.poseName) }
}
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PoseableEntityState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("gimmighoul_chest", "faint") else null
}
@@ -1,70 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen9
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BimanualSwingAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.ModelPart
import net.minecraft.util.math.Vec3d
class GimmighoulRoamingModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame, BipedFrame, BimanualFrame {
override val rootPart = root.registerChildWithAllChildren("gimmighoul_roaming")
override val head = getPart("head")
override val leftArm = getPart("arm_left")
override val rightArm = getPart("arm_right")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
override val portraitScale = 2.5F
override val portraitTranslation = Vec3d(0.0, -1.3, 0.0)
override val profileScale = 0.7F
override val profileTranslation = Vec3d(0.0, 0.76, 0.0)
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
override fun registerPoses() {
val blink = quirk { bedrockStateful("gimmighoul_roaming", "blink") }
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("gimmighoul_roaming", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("gimmighoul_roaming", "ground_idle"),
BipedWalkAnimation(this, periodMultiplier = 0.6F, amplitudeMultiplier = 0.9F),
BimanualSwingAnimation(this, swingPeriodMultiplier = 0.6F, amplitudeMultiplier = 0.9F)
//bedrock("gimmighoul_roaming", "ground_walk")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PoseableEntityState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("gimmighoul_roaming", "faint") else null
}
@@ -1,63 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.repository
import com.cobblemon.mod.common.client.render.models.blockbench.blockentity.BlockEntityModel
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.JsonPokemonPoseableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Bone
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.fromJson
import com.google.gson.GsonBuilder
import com.google.gson.JsonObject
import net.minecraft.entity.Entity
/**
* This is specifically for BlockEntities where we want to do more complex animation than what Java Edition already allows
* Basically with Java Edition, we can only change the texture applied to a model, if we want to move bones around, need to
* do something else, so we use this
*/
object BlockEntityModelRepository : VaryingModelRepository<Entity, BlockEntityModel>() {
override val title = "Block Entity"
override val type = "block_entities"
override val variationDirectories: List<String> = listOf("bedrock/$type/variations", "bedrock/$type")
override val poserDirectories: List<String> = listOf("bedrock/$type/posers")
override val modelDirectories: List<String> = listOf("bedrock/$type/models")
override val animationDirectories: List<String> = listOf("bedrock/$type/animations")
override val fallback = cobblemonResource("substitute")
override val isForLivingEntityRenderer = false
private val gson = GsonBuilder().create()
override fun loadJsonPoser(json: String): (Bone) -> BlockEntityModel {
val jsonObject = gson.fromJson<JsonObject>(json)
val animations = jsonObject.getAsJsonArray("animations")
val maxScale = jsonObject.get("maxScale")?.asFloat ?: 1F
val yTranslation = jsonObject.get("yTranslation")?.asFloat ?: 0F
return { bone ->
val model = BlockEntityModel(bone)
model.maxScale = maxScale
model.yTranslation = yTranslation
// I stole all this from FossilModelRepository, so I guess I'll leave the comments here
//
// Refactor this bullshit to not mention pokemon at all, it should be common to anything using animation factories.
// Even better: move to molang functions, this is ass
model.idleAnimations = animations.mapNotNull {
val animString = it.asString
val anim = animString.substringBefore("(")
if (JsonPokemonPoseableModel.ANIMATION_FACTORIES.contains(anim)) {
return@mapNotNull JsonPokemonPoseableModel.ANIMATION_FACTORIES[anim]!!.stateless(model, animString)
} else {
null
}
}.toTypedArray()
model
}
}
override fun registerInBuiltPosers() {}
}
@@ -588,9 +588,6 @@ object PokemonModelRepository : VaryingModelRepository<PokemonEntity, PokemonPos
inbuilt("litwick", ::LitwickModel)
inbuilt("lampent", ::LampentModel)
inbuilt("chandelure", ::ChandelureModel)
inbuilt("gimmighoulroaming", ::GimmighoulRoamingModel)
inbuilt("gimmighoulchest", ::GimmighoulChestModel)
inbuilt("gholdengo", ::GholdengoModel)
inbuilt("drifloon", ::DrifloonModel)
inbuilt("drifblim", ::DrifblimModel)
}
@@ -16,25 +16,35 @@ import com.cobblemon.mod.common.client.entity.PokemonClientDelegate.Companion.BE
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate.Companion.BEAM_SHRINK_TIME
import com.cobblemon.mod.common.client.keybind.boundKey
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding
import com.cobblemon.mod.common.client.render.addVertex
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityModel
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokeBallModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.parabolaFunction
import com.cobblemon.mod.common.client.render.pokeball.PokeBallPoseableState
import com.cobblemon.mod.common.client.render.renderBeaconBeam
import com.cobblemon.mod.common.client.settings.ServerSettings
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity.Companion.SPAWN_DIRECTION
import com.cobblemon.mod.common.pokeball.PokeBall
import com.cobblemon.mod.common.util.isLookingAt
import com.cobblemon.mod.common.util.lang
import com.cobblemon.mod.common.util.math.DoubleRange
import com.cobblemon.mod.common.util.math.geometry.toRadians
import com.cobblemon.mod.common.util.math.remap
import kotlin.math.*
import com.mojang.blaze3d.systems.RenderSystem
import net.minecraft.client.MinecraftClient
import net.minecraft.client.font.TextRenderer
import net.minecraft.client.gl.GlUniform
import net.minecraft.client.gl.ShaderProgram
import net.minecraft.client.gl.Uniform
import net.minecraft.client.render.GameRenderer
import net.minecraft.client.render.LightmapTextureManager
import net.minecraft.client.render.RenderLayer
import net.minecraft.client.render.RenderPhase
import net.minecraft.client.render.VertexConsumerProvider
import net.minecraft.client.network.ClientPlayerEntity
import net.minecraft.client.render.*
import net.minecraft.client.render.entity.EntityRendererFactory
import net.minecraft.client.render.entity.MobEntityRenderer
@@ -42,6 +52,7 @@ import net.minecraft.client.render.entity.model.EntityModel
import net.minecraft.client.render.item.ItemRenderer
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.entity.Entity
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.text.Text
import net.minecraft.util.Identifier
@@ -53,6 +64,12 @@ import org.joml.Math
import org.joml.Quaternionf
import org.joml.Vector3f
import org.joml.Vector4f
import kotlin.math.*
import kotlin.properties.Delegates
import kotlin.math.max
import kotlin.math.min
import kotlin.math.sin
import kotlin.math.tan
class PokemonRenderer(
context: EntityRendererFactory.Context
@@ -111,12 +128,6 @@ class PokemonRenderer(
// progressUniform?.set((sin(entity.ticksLived/20f) + 1f)/2f)
// }
// }
if (entity.ticksLived < 10) {
entity.bodyYaw = entity.dataTracker.get(SPAWN_DIRECTION)
entity.prevBodyYaw = entity.bodyYaw
}
super.render(entity, entityYaw, partialTicks, poseMatrix, buffer, packedLight)
modelNow.green = 1F
@@ -26,15 +26,13 @@ class ClientParty(uuid: UUID, slots: Int) : ClientStorage<PartyPosition>(uuid),
fun get(slot: Int) = get(PartyPosition(slot))
override fun get(position: PartyPosition): Pokemon? {
if (position.slot >= slots.size || position.slot == -1) {
if (position.slot >= slots.size) {
return null
}
return slots[position.slot]
}
fun isEmpty() = (slots.size == 0)
fun getPosition(pokemonID: UUID) = slots.indexOfFirst { it?.uuid == pokemonID }
override fun getPosition(pokemon: Pokemon): PartyPosition? {
for (slotNumber in slots.indices) {
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.command
import com.cobblemon.mod.common.api.permission.CobblemonPermissions
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.command.argument.PokemonPropertiesArgumentType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.alias
import com.cobblemon.mod.common.util.commandLang
import com.cobblemon.mod.common.util.permission
@@ -72,7 +71,6 @@ object SpawnPokemon {
}
val pokemonEntity = properties.createEntity(world)
pokemonEntity.refreshPositionAndAngles(pos.x, pos.y, pos.z, pokemonEntity.yaw, pokemonEntity.pitch)
pokemonEntity.dataTracker.set(PokemonEntity.SPAWN_DIRECTION, pokemonEntity.random.nextFloat() * 360F)
if (world.spawnEntity(pokemonEntity)) {
return Command.SINGLE_SUCCESS
}
@@ -13,21 +13,21 @@ import com.cobblemon.mod.common.CobblemonEntities
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
import com.cobblemon.mod.common.api.scheduling.taskBuilder
import com.cobblemon.mod.common.api.text.text
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.actor.PlayerBattleActor
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.entity.fallingstar.FallingStarEntity
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
import com.cobblemon.mod.common.particle.SnowstormParticleReader
import com.cobblemon.mod.common.trade.ActiveTrade
import com.cobblemon.mod.common.trade.DummyTradeParticipant
import com.cobblemon.mod.common.trade.PlayerTradeParticipant
import com.cobblemon.mod.common.util.fromJson
import com.cobblemon.mod.common.util.party
import com.cobblemon.mod.common.util.toPokemon
import com.cobblemon.mod.common.util.*
import com.google.gson.GsonBuilder
import com.google.gson.JsonObject
import com.mojang.brigadier.Command
@@ -57,6 +57,9 @@ object TestCommand {
return Command.SINGLE_SUCCESS
}
val player = context.source.player as ServerPlayerEntity
player.sendMessageToClient("There are ".text().append(player.world.getChunk(player.pos.toBlockPos()).getDyniteOre().toString().text().append(" blocks of Dynite Ore in this chunk".text())), false)
try {
// readBerryDataFromCSV()
@@ -32,8 +32,6 @@ enum class PoseType {
PROFILE,
/** A pose for rendering in the party overlay and in minor spaces like the battle tiles. */
PORTRAIT,
/** For guilded chest */
OPEN,
/** A simple type for non-living entities or errant cases. */
NONE;
@@ -0,0 +1,162 @@
/*
* 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.entity.fallingstar
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonEntities
import com.cobblemon.mod.common.api.spawning.BestSpawner
import com.cobblemon.mod.common.api.spawning.fallingstar.FallingStarSpawnCause
import com.cobblemon.mod.common.loot.CobblemonLootTables
import com.cobblemon.mod.common.util.math.DoubleRange
import com.cobblemon.mod.common.util.nextBetween
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
import net.minecraft.entity.Entity
import net.minecraft.entity.ItemEntity
import net.minecraft.entity.MovementType
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.loot.context.LootContextParameterSet
import net.minecraft.loot.context.LootContextParameters
import net.minecraft.loot.context.LootContextTypes
import net.minecraft.nbt.NbtCompound
import net.minecraft.server.world.ServerWorld
import net.minecraft.sound.SoundCategory
import net.minecraft.sound.SoundEvents
import net.minecraft.util.Identifier
import net.minecraft.util.math.Vec3d
import net.minecraft.world.World
import net.minecraft.world.explosion.Explosion
import java.time.Instant
import kotlin.random.Random
class FallingStarEntity(world: World) : Entity(CobblemonEntities.FALLING_STAR_ENTITY, world) {
private var particleOne = Identifier("cobblemon:null")
private var particleTwo = Identifier("cobblemon:null")
private var particleThree = Identifier("cobblemon:null")
private var particleAmbient = Identifier("cobblemon:null")
private var particleImpact = Identifier("cobblemon:null")
private var particleTimer: Instant = Instant.now().plusMillis(50)
private var particleAmbientTimer: Instant = Instant.now().plusMillis(1000)
private var hasFallen = false
override fun initDataTracker() {
}
override fun readCustomDataFromNbt(nbt: NbtCompound?) {
}
override fun writeCustomDataToNbt(nbt: NbtCompound?) {
}
override fun tick() {
particleOne = Identifier("cobblemon:meteor_glitter")
particleTwo = Identifier("cobblemon:meteor_trail")
particleThree = Identifier("cobblemon:meteor_falling")
if (velocity.y == 0.0) {
velocity = Vec3d(Random.nextBetween(VELOCITY_RANGE.start, VELOCITY_RANGE.endInclusive), -1.0, Random.nextBetween(VELOCITY_RANGE.start, VELOCITY_RANGE.endInclusive))
particleOne = Identifier("cobblemon:null")
particleTwo = Identifier("cobblemon:null")
particleThree = Identifier("cobblemon:null")
if (Instant.now().isAfter(particleAmbientTimer)) {
particleAmbient = Identifier("cobblemon:meteor_ambient")
particleHandler(particleAmbient, this.pos)
particleAmbientTimer = Instant.now().plusMillis(1000)
}
}
if (!world.getBlockState(blockPos.down()).isAir) {
velocity = Vec3d(0.0, -1.0, 0.0)
if (!world.isClient && !hasFallen) {
particleImpact = Identifier("cobblemon:meteor_impact")
particleHandler(particleImpact, this.pos)
(world as ServerWorld).createExplosion(
this,
x, y, z, // the position of the explosion
0.0f, // the power of the explosion
World.ExplosionSourceType.MOB
)
hasFallen = true
}
}
move(MovementType.SELF, velocity)
val player = closestPlayer
if (player != null) {
reveal(player)
kill()
}
if(Instant.now().isAfter(particleTimer)) {
particleHandler(particleTwo, this.pos)
particleHandler(particleThree, this.pos)
particleTimer = Instant.now().plusMillis(50)
}
particleHandler(particleOne, this.pos)
super.tick()
}
private fun reveal(playerEntity: PlayerEntity) {
world.playSound(null, blockPos, SoundEvents.ENTITY_PLAYER_LEVELUP, SoundCategory.AMBIENT)
val random = random.nextBetween(0, 100)
if (random <= 50) {
spawnPokemon(playerEntity)
} else {
spawnItem()
}
}
private fun spawnItem() {
if (world.isClient) return
val lootTable = world.server?.lootManager?.getLootTable(CobblemonLootTables.FALLING_STAR) ?: return
val stacks = lootTable.generateLoot(LootContextParameterSet.Builder(world as ServerWorld)
.add(LootContextParameters.THIS_ENTITY, this)
.build(LootContextTypes.BARTER))
stacks.forEach { world.spawnEntity(ItemEntity(world, pos.x, pos.y, pos.z, it)) }
particleOne = Identifier("cobblemon:masterball/ballsparkle")
particleHandler(particleOne, this.pos)
}
private fun spawnPokemon(playerEntity: PlayerEntity) {
if (world.isClient) return
val spawner = BestSpawner.starSpawner
val spawnCause = FallingStarSpawnCause(
spawner = spawner,
bucket = Cobblemon.bestSpawner.config.buckets[0],
entity = playerEntity
)
particleOne = Identifier("cobblemon:confetti")
particleHandler(particleOne, this.pos)
val result = spawner.run(spawnCause, world as ServerWorld, blockPos) ?: return
}
private fun particleHandler(id: Identifier, pos: Vec3d) {
val spawnSnowstormParticlePacket = SpawnSnowstormParticlePacket(id, pos)
spawnSnowstormParticlePacket.sendToPlayersAround(pos.x, pos.y, pos.z, 128.0, world.registryKey)
}
override fun shouldRender(distance: Double): Boolean {
return false
}
private val closestPlayer: PlayerEntity?
get() = world.players.firstOrNull { it.pos.distanceTo(pos) < 6.0 }
companion object {
val VELOCITY_RANGE = DoubleRange(-0.25, 0.25)
}
}
@@ -0,0 +1,647 @@
/*
* 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.entity.fishing
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonEntities
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.spawning.*
import com.cobblemon.mod.common.api.spawning.context.AreaContextResolver
import com.cobblemon.mod.common.api.spawning.detail.EntitySpawnResult
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnAction
import com.cobblemon.mod.common.api.spawning.detail.SingleEntitySpawnAction
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawnCause
import com.cobblemon.mod.common.api.spawning.influence.PlayerLevelRangeInfluence
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.api.spawning.rules.SpawnRule
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
import com.cobblemon.mod.common.api.spawning.spawner.SpawningArea
import com.cobblemon.mod.common.api.text.green
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.battles.BattleBuilder
import com.cobblemon.mod.common.command.SpawnPokemonFromPool
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokemonPacket
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.commandLang
import com.cobblemon.mod.common.util.isServerSide
import com.cobblemon.mod.common.util.party
import com.cobblemon.mod.common.util.toBlockPos
import com.mongodb.internal.connection.Server
import net.minecraft.advancement.criterion.Criteria
import net.minecraft.block.Blocks
import net.minecraft.enchantment.Enchantment
import net.minecraft.enchantment.Enchantments
import net.minecraft.entity.*
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.projectile.FishingBobberEntity
import net.minecraft.entity.projectile.ProjectileUtil
import net.minecraft.item.ItemStack
import net.minecraft.loot.LootTables
import net.minecraft.loot.context.LootContextParameterSet
import net.minecraft.loot.context.LootContextParameters
import net.minecraft.loot.context.LootContextTypes
import net.minecraft.nbt.NbtCompound
import net.minecraft.nbt.NbtList
import net.minecraft.nbt.NbtType
import net.minecraft.particle.ParticleTypes
import net.minecraft.registry.Registries
import net.minecraft.registry.tag.FluidTags
import net.minecraft.registry.tag.ItemTags
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.server.world.ServerWorld
import net.minecraft.sound.SoundEvents
import net.minecraft.stat.Stats
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.MathHelper
import net.minecraft.util.math.Vec3d
import net.minecraft.util.math.random.Random
import kotlin.random.*
import net.minecraft.world.World
import java.util.*
class PokeRodFishingBobberEntity(type: EntityType<out PokeRodFishingBobberEntity>, world: World) : FishingBobberEntity(type, world) {
private val velocityRandom = Random.create()
private val caughtFish = false
private var outOfOpenWaterTicks = 0
private val field_30665 = 10
// todo is this needed?
//val HOOK_ENTITY_ID = DataTracker.registerData(PokeRodFishingBobberEntity::class.java, TrackedDataHandlerRegistry.INTEGER)
//private val CAUGHT_FISH = DataTracker.registerData(PokeRodFishingBobberEntity::class.java, TrackedDataHandlerRegistry.BOOLEAN)
// todo if so replace these later
var HOOK_ENTITY_ID = 0
var CAUGHT_FISH = false
private var removalTimer = 0
private var hookCountdown = 0
private var waitCountdown = 0
private var fishTravelCountdown = 0
private var fishAngle = 0f
private var inOpenWater = true
private var hookedEntity: Entity? = null
private var state = State.FLYING
private var luckOfTheSeaLevel = 0
private var lureLevel = 0
private var typeCaught= "ITEM"
private var chosenBucket = Cobblemon.bestSpawner.config.buckets[0] // default to first rarity bucket
private var rarityCaught = "COMMON"
private val pokemonSpawnChance = 70 // chance a Pokemon will be fished up % out of 100
constructor(thrower: PlayerEntity, world: World, luckOfTheSea: Int, lure: Int) : this(CobblemonEntities.POKE_BOBBER, world) {
// Copy pasta a LOT
//this(CobblemonEntities.POKE_BOBBER, world, luckOfTheSeaLevel, lureLevel)
owner = thrower
luckOfTheSeaLevel = luckOfTheSea
lureLevel = lure
val f = thrower.pitch
val g = thrower.yaw
val h = MathHelper.cos(-g * 0.017453292f - 3.1415927f)
val i = MathHelper.sin(-g * 0.017453292f - 3.1415927f)
val j = -MathHelper.cos(-f * 0.017453292f)
val k = MathHelper.sin(-f * 0.017453292f)
val d = thrower.x - i.toDouble() * 0.3
val e = thrower.eyeY
val l = thrower.z - h.toDouble() * 0.3
this.refreshPositionAndAngles(d, e, l, g, f)
var vec3d = Vec3d((-i).toDouble(), MathHelper.clamp(-(k / j), -5.0f, 5.0f).toDouble(), (-h).toDouble())
val m = vec3d.length()
vec3d = vec3d.multiply(0.6 / m + random.nextTriangular(0.5, 0.0103365), 0.6 / m + random.nextTriangular(0.5, 0.0103365), 0.6 / m + random.nextTriangular(0.5, 0.0103365))
velocity = vec3d
yaw = (MathHelper.atan2(vec3d.x, vec3d.z) * 57.2957763671875).toFloat()
pitch = (MathHelper.atan2(vec3d.y, vec3d.horizontalLength()) * 57.2957763671875).toFloat()
prevYaw = yaw
prevPitch = pitch
}
fun calculateMinMaxCountdown(weight: Float): Pair<Int, Int> {
// Constants for the target min and max values at weight extremes
val minAtMaxWeight = 20
val maxAtMaxWeight = 40
val minAtMinWeight = 15
val maxAtMinWeight = 20
// Calculate factors for min and max based on the weight
val minFactor = ((minAtMaxWeight - minAtMinWeight) / 100f) * weight + minAtMinWeight
val maxFactor = ((maxAtMaxWeight - maxAtMinWeight) / 100f) * weight + maxAtMinWeight
// Ensure min and max are within the needed bounds
val min = minFactor.toInt().coerceIn(minAtMinWeight, minAtMaxWeight)
val max = maxFactor.toInt().coerceIn(maxAtMinWeight, maxAtMaxWeight)
return Pair(min, max)
}
fun chooseAdjustedSpawnBucket(buckets: List<SpawnBucket>, luckOfTheSeaLevel: Int): SpawnBucket {
val baseIncreases = listOf(5.0F, 1.0F, 0.2F) // Base increases for the first three buckets beyond the first
val adjustedWeights = buckets.mapIndexed { index, bucket ->
if (index == 0) {
// Placeholder, will be recalculated
0.0F
} else {
val increase = if (index < baseIncreases.size) baseIncreases[index] else baseIncreases.last() + (index - baseIncreases.size + 1) * 0.15F
bucket.weight + increase * luckOfTheSeaLevel
}
}.toMutableList()
// Recalculate the first bucket's weight to ensure the total is 100%
val totalAdjustedWeight = adjustedWeights.sum() - adjustedWeights[0] // Corrected to ensure the list contains Floats
adjustedWeights[0] = 100.0F - totalAdjustedWeight + buckets[0].weight
// Random selection based on adjusted weights
val weightSum = adjustedWeights.sum()
val chosenSum = kotlin.random.Random.nextDouble(weightSum.toDouble()).toFloat() // Ensure usage of Random from kotlin.random package
var sum = 0.0F
adjustedWeights.forEachIndexed { index, weight ->
sum += weight
if (sum >= chosenSum) {
return buckets[index]
}
}
return buckets.first() // Fallback
}
/*// make more generic version for other enchants. Pass in id of enchant
fun getEnchantLevel(enchantment: Enchantment): Int {
var pokerodEnchantments: NbtList? = null
if (owner?.isPlayer == true) {
pokerodEnchantments = (owner as PlayerEntity).mainHandStack?.enchantments
}
val luckOfTheSeaEnchantment = pokerodEnchantments?.filter {
if (it is NbtCompound)
if (it.getString("id") == Registries.ENCHANTMENT.getEntry(enchantment).key.toString())
return@filter true
return@filter false
}?.first()
return (luckOfTheSeaEnchantment as? NbtCompound)?.getShort("lvl")?.toInt() ?: 0
}*/
fun isOpenOrWaterAround(pos: BlockPos): Boolean {
var positionType = PositionType.INVALID
for (i in -1..2) {
val positionType2 = this.getPositionType(pos.add(-2, i, -2), pos.add(2, i, 2))
when (positionType2) {
PositionType.INVALID -> return false
PositionType.ABOVE_WATER -> if (positionType == PositionType.INVALID) {
return false
}
PositionType.INSIDE_WATER -> if (positionType == PositionType.ABOVE_WATER) {
return false
}
else -> return false
}
positionType = positionType2
}
return true
}
/*private fun getPositionType(start: BlockPos, end: BlockPos): PokeRodFishingBobberEntity.PositionType? {
return BlockPos.stream(start, end).map { pos: BlockPos? -> this.getPositionType(pos!!) }.reduce { positionType: PokeRodFishingBobberEntity.PositionType, positionType2: PokeRodFishingBobberEntity.PositionType -> if (positionType == positionType2) positionType else PokeRodFishingBobberEntity.PositionType.INVALID } as ((PositionType?, PositionType?) -> PositionType?)?.orElse(PokeRodFishingBobberEntity.PositionType.INVALID) as PokeRodFishingBobberEntity.PositionType
}*/
private fun getPositionType(start: BlockPos, end: BlockPos): PositionType? {
return BlockPos.stream(start, end)
.map { pos -> this.getPositionType(pos) }
.reduce { positionType, positionType2 ->
if (positionType == positionType2) positionType else PositionType.INVALID
}.orElse(PositionType.INVALID)
}
private fun getPositionType(pos: BlockPos): PositionType {
val blockState = world.getBlockState(pos)
return if (!blockState.isAir && !blockState.isOf(Blocks.LILY_PAD)) {
val fluidState = blockState.fluidState
if (fluidState.isIn(FluidTags.WATER) && fluidState.isStill && blockState.getCollisionShape(world, pos).isEmpty) PositionType.INSIDE_WATER else PositionType.INVALID
} else {
PositionType.ABOVE_WATER
}
}
enum class PositionType {
ABOVE_WATER,
INSIDE_WATER,
INVALID
}
private fun setPlayerFishHook(fishingBobber: FishingBobberEntity?) {
val playerEntity = this.playerOwner
if (playerEntity != null) {
playerEntity.fishHook = fishingBobber
}
}
internal enum class State {
FLYING,
HOOKED_IN_ENTITY,
BOBBING
}
// todo custom behavior for fishing logic
private fun tickFishingLogic(pos: BlockPos) {
val serverWorld = world as ServerWorld
var i = 1
val blockPos = pos.up()
if (random.nextFloat() < 0.25f && world.hasRain(blockPos)) {
++i
}
if (random.nextFloat() < 0.5f && !world.isSkyVisible(blockPos)) {
--i
}
if (this.hookCountdown > 0) {
--this.hookCountdown
if (this.hookCountdown <= 0) {
this.waitCountdown = 0
this.fishTravelCountdown = 0
this.CAUGHT_FISH = false
//getDataTracker().set(CAUGHT_FISH, false)
}
} else if (this.fishTravelCountdown > 0) {
this.fishTravelCountdown -= i
if (this.fishTravelCountdown > 0) {
var j: Double
var e: Double
this.fishAngle += random.nextTriangular(0.0, 9.188).toFloat()
val f = this.fishAngle * (Math.PI.toFloat() / 180)
val g = MathHelper.sin(f)
val h = MathHelper.cos(f)
val d = this.x + (g * this.fishTravelCountdown.toFloat() * 0.1f).toDouble()
val blockState = serverWorld.getBlockState(BlockPos.ofFloored(d, (MathHelper.floor(this.y).toFloat() + 1.0f).toDouble().also { e = it } - 1.0, this.z + (h * this.fishTravelCountdown.toFloat() * 0.1f).toDouble().also { j = it }))
if (blockState.isOf(Blocks.WATER)) {
if (random.nextFloat() < 0.15f) {
serverWorld.spawnParticles(ParticleTypes.BUBBLE, d, e - 0.1, j, 1, g.toDouble(), 0.1, h.toDouble(), 0.0)
}
val k = g * 0.04f
val l = h * 0.04f
serverWorld.spawnParticles(ParticleTypes.FISHING, d, e, j, 0, l.toDouble(), 0.01, -k.toDouble(), 1.0)
serverWorld.spawnParticles(ParticleTypes.FISHING, d, e, j, 0, -l.toDouble(), 0.01, k.toDouble(), 1.0)
}
} else {
playSound(SoundEvents.ENTITY_FISHING_BOBBER_SPLASH, 0.25f, 1.0f + (random.nextFloat() - random.nextFloat()) * 0.4f)
val m = this.y + 0.5
serverWorld.spawnParticles(ParticleTypes.BUBBLE, this.x, m, this.z, (1.0f + this.width * 20.0f).toInt(), this.width.toDouble(), 0.0, this.width.toDouble(), 0.2)
serverWorld.spawnParticles(ParticleTypes.FISHING, this.x, m, this.z, (1.0f + this.width * 20.0f).toInt(), this.width.toDouble(), 0.0, this.width.toDouble(), 0.2)
// TODO find a way to make luck of the sea environment increase odds of getting better rarity rates
if (MathHelper.nextInt(random, 0, 100) < this.pokemonSpawnChance) {
// todo do another chance check for rarity and then set typeCaught
this.typeCaught = "POKEMON"
val buckets = Cobblemon.bestSpawner.config.buckets
// choose a spawn bucket according to weights no matter how many there are
chosenBucket = chooseAdjustedSpawnBucket(buckets, luckOfTheSeaLevel)
val reactionMinMax = calculateMinMaxCountdown(chosenBucket.weight)
// set the hook reaction time to be based off the rarity of the bucket chosen
this.hookCountdown = MathHelper.nextInt(random, reactionMinMax.first, reactionMinMax.second)
System.out.println("Player hooked a Pokemon from the bucket: " + chosenBucket.name);
/*if (MathHelper.nextDouble(random, 0.0, 100.0) < this.commonSpawnChance) {
// todo set common spawn
this.hookCountdown = MathHelper.nextInt(random, 20, 40)
this.rarityCaught = "COMMON"
System.out.println("Player hooked a Common Pokemon");
}
else {
if (MathHelper.nextDouble(random, 0.0, 100.0 - this.commonSpawnChance) < this.uncommonSpawnChance) {
// todo set uncommon spawn
this.hookCountdown = MathHelper.nextInt(random, 20, 35)
this.rarityCaught = "UNCOMMON"
System.out.println("Player hooked a Uncommon Pokemon");
}
else {
if (MathHelper.nextDouble(random, 0.0, 100.0 - this.commonSpawnChance - this.uncommonSpawnChance) < this.rareSpawnChance) {
// todo set rare spawn
this.hookCountdown = MathHelper.nextInt(random, 20, 30)
this.rarityCaught = "RARE"
System.out.println("Player hooked a Rare Pokemon");
}
else {
// todo set ultra-rare spawn chance
this.hookCountdown = MathHelper.nextInt(random, 20, 25)
this.rarityCaught = "ULTRA-RARE"
System.out.println("Player hooked an Ultra-Rare Pokemon");
}
}
}*/
}
else {
// todo caught item
this.typeCaught = "ITEM"
this.hookCountdown = MathHelper.nextInt(random, 20, 40)
}
//this.hookCountdown = MathHelper.nextInt(random, 20, 40)
//getDataTracker().set(CAUGHT_FISH, true)
this.CAUGHT_FISH = true
}
} else if (this.waitCountdown > 0) {
this.waitCountdown -= i
var f = 0.15f
if (this.waitCountdown < 20) {
f += (20 - this.waitCountdown).toFloat() * 0.05f
} else if (this.waitCountdown < 40) {
f += (40 - this.waitCountdown).toFloat() * 0.02f
} else if (this.waitCountdown < 60) {
f += (60 - this.waitCountdown).toFloat() * 0.01f
}
if (random.nextFloat() < f) {
var j: Double
var e: Double
val g = MathHelper.nextFloat(random, 0.0f, 360.0f) * (Math.PI.toFloat() / 180)
val h = MathHelper.nextFloat(random, 25.0f, 60.0f)
val d = this.x + (MathHelper.sin(g) * h).toDouble() * 0.1
val blockState = serverWorld.getBlockState(BlockPos.ofFloored(d, (MathHelper.floor(this.y).toFloat() + 1.0f).toDouble().also { e = it } - 1.0, this.z + (MathHelper.cos(g) * h).toDouble() * 0.1.also { j = it }))
if (blockState.isOf(Blocks.WATER)) {
serverWorld.spawnParticles(ParticleTypes.SPLASH, d, e, j, 2 + random.nextInt(2), 0.1, 0.0, 0.1, 0.0)
}
}
if (this.waitCountdown <= 0) {
this.fishAngle = MathHelper.nextFloat(random, 0.0f, 360.0f)
this.fishTravelCountdown = MathHelper.nextInt(random, 20, 80)
}
} else {
this.waitCountdown = MathHelper.nextInt(random, 100, 600)
this.waitCountdown -= this.lureLevel * 20 * 5
}
}
private fun removeIfInvalid(player: PlayerEntity): Boolean {
val itemStack = player.mainHandStack
val itemStack2 = player.offHandStack
val bl = itemStack.isOf(CobblemonItems.POKEROD)
val bl2 = itemStack2.isOf(CobblemonItems.POKEROD)
if (player.isRemoved || !player.isAlive || !bl && !bl2 || this.squaredDistanceTo(player) > 1024.0) {
discard()
return true
}
return false
}
private fun checkForCollision() {
val hitResult = ProjectileUtil.getCollision(this) { entity: Entity? -> this.canHit(entity) }
onCollision(hitResult)
}
private fun updateHookedEntityId(entity: Entity?) {
this.hookedEntity = entity
//getDataTracker().set(HOOK_ENTITY_ID, if (entity == null) 0 else entity.id + 1)
this.HOOK_ENTITY_ID = if (entity == null) 0 else entity.id + 1
}
override fun tick() {
velocityRandom.setSeed(getUuid().leastSignificantBits xor world.time)
//super.tick()
val playerEntity = this.playerOwner
if (playerEntity == null) {
discard()
} else if (world.isClient || !removeIfInvalid(playerEntity)) {
if (this.isOnGround) {
++removalTimer
if (removalTimer >= 1200) {
discard()
return
}
} else {
removalTimer = 0
}
var f = 0.0f
val blockPos = blockPos
val fluidState = world.getFluidState(blockPos)
if (fluidState.isIn(FluidTags.WATER)) {
f = fluidState.getHeight(world, blockPos)
}
val bl = f > 0.0f
if (state == State.FLYING) {
if (hookedEntity != null) {
velocity = Vec3d.ZERO
state = State.HOOKED_IN_ENTITY
return
}
if (bl) {
velocity = velocity.multiply(0.3, 0.2, 0.3)
state = State.BOBBING
return
}
checkForCollision()
} else {
if (state == State.HOOKED_IN_ENTITY) {
if (hookedEntity != null) {
if (!hookedEntity!!.isRemoved && hookedEntity!!.world.registryKey === world.registryKey) {
this.setPosition(hookedEntity!!.x, hookedEntity!!.getBodyY(0.8), hookedEntity!!.z)
} else {
updateHookedEntityId(null as Entity?)
state = State.FLYING
}
}
return
}
if (state == State.BOBBING) {
val vec3d = velocity
var d = this.y + vec3d.y - blockPos.y.toDouble() - f.toDouble()
if (Math.abs(d) < 0.01) {
d += Math.signum(d) * 0.1
}
this.setVelocity(vec3d.x * 0.9, vec3d.y - d * random.nextFloat().toDouble() * 0.2, vec3d.z * 0.9)
if (hookCountdown <= 0 && fishTravelCountdown <= 0) {
inOpenWater = true
} else {
inOpenWater = inOpenWater && outOfOpenWaterTicks < 10 && isOpenOrWaterAround(blockPos)
}
if (bl) {
outOfOpenWaterTicks = Math.max(0, outOfOpenWaterTicks - 1)
if (caughtFish) {
velocity = velocity.add(0.0, -0.1 * velocityRandom.nextFloat().toDouble() * velocityRandom.nextFloat().toDouble(), 0.0)
}
if (!world.isClient) {
tickFishingLogic(blockPos)
}
} else {
outOfOpenWaterTicks = Math.min(10, outOfOpenWaterTicks + 1)
}
}
}
if (!fluidState.isIn(FluidTags.WATER)) {
velocity = velocity.add(0.0, -0.03, 0.0)
}
move(MovementType.SELF, velocity)
this.updateRotation()
if (state == State.FLYING && (this.isOnGround || horizontalCollision)) {
velocity = Vec3d.ZERO
}
val e = 0.92 // air friction??
velocity = velocity.multiply(0.92)
refreshPosition()
}
}
override fun use(usedItem: ItemStack): Int {
val playerEntity = this.playerOwner
return if (!world.isClient && playerEntity != null && !removeIfInvalid(playerEntity)) {
var i = 0
if (this.hookedEntity != null) {
pullHookedEntity(this.hookedEntity)
Criteria.FISHING_ROD_HOOKED.trigger(playerEntity as ServerPlayerEntity?, usedItem, this, emptyList())
world.sendEntityStatus(this, 31.toByte())
i = if (this.hookedEntity is ItemEntity) 3 else 5
} else if (this.hookCountdown > 0) {
// check if thing caught was an item
if (this.typeCaught == "ITEM") {
val lootContextParameterSet = LootContextParameterSet.Builder(world as ServerWorld).add(LootContextParameters.ORIGIN, pos).add(LootContextParameters.TOOL, usedItem).add(LootContextParameters.THIS_ENTITY, this).luck(this.luckOfTheSeaLevel.toFloat() + playerEntity.luck).build(LootContextTypes.FISHING)
val lootTable = world.server!!.lootManager.getLootTable(LootTables.FISHING_GAMEPLAY)
val list: List<ItemStack> = lootTable.generateLoot(lootContextParameterSet)
Criteria.FISHING_ROD_HOOKED.trigger(playerEntity as ServerPlayerEntity?, usedItem, this, list)
val var7: Iterator<*> = list.iterator()
while (var7.hasNext()) {
val itemStack = var7.next() as ItemStack
val itemEntity = ItemEntity(world, this.x, this.y, this.z, itemStack)
val d = playerEntity.getX() - this.x
val e = playerEntity.getY() - this.y
val f = playerEntity.getZ() - this.z
val g = 0.1
itemEntity.setVelocity(d * 0.1, e * 0.1 + Math.sqrt(Math.sqrt(d * d + e * e + f * f)) * 0.08, f * 0.1)
world.spawnEntity(itemEntity)
playerEntity.getWorld().spawnEntity(ExperienceOrbEntity(playerEntity.getWorld(), playerEntity.getX(), playerEntity.getY() + 0.5, playerEntity.getZ() + 0.5, random.nextInt(6) + 1))
if (itemStack.isIn(ItemTags.FISHES)) {
playerEntity.increaseStat(Stats.FISH_CAUGHT, 1)
}
}
i = 1
}
else { // logic for spawning Pokemon using rarity
System.out.println("Player reeled in a Pokemon from the bucket: " + chosenBucket.name)
val bobberOwner = playerOwner as ServerPlayerEntity
// spawn the pokemon from the chosen bucket at the bobber's location
spawnPokemonFromFishing(bobberOwner, this, chosenBucket)
val serverWorld = world as ServerWorld
val g = MathHelper.nextFloat(random, 0.0f, 360.0f) * (Math.PI.toFloat() / 180)
val h = MathHelper.nextFloat(random, 25.0f, 60.0f)
val partX = this.x + (MathHelper.sin(g) * h).toDouble() * 0.1
serverWorld.spawnParticles(ParticleTypes.SPLASH, partX, this.y, this.z, 4 + random.nextInt(4), 0.1, 0.0, 0.1, 0.0)
playerEntity.getWorld().spawnEntity(ExperienceOrbEntity(playerEntity.getWorld(), playerEntity.getX(), playerEntity.getY() + 0.5, playerEntity.getZ() + 0.5, random.nextInt(6) + 1))
val bobberBiome = world.getBiome(this.blockPos) // biome of the bobber. But idk if we need this. Probably not anymore
}
}
if (this.isOnGround) {
i = 2
}
discard()
i
} else {
0
}
}
fun spawnPokemonFromFishing(player: PlayerEntity, bobber: PokeRodFishingBobberEntity, chosenBucket: SpawnBucket) {
var hookedEntityID: Int? = null
var hookedEntity: Entity? = null
val spawner = BestSpawner.fishingSpawner
// stealing a ton of stuff from the SpawnFromPool Command
//val spawnCause = SpawnCause(spawner = spawner, bucket = spawner.chooseBucket(), entity = spawner.getCauseEntity())
val spawnCause = FishingSpawnCause(
spawner = spawner,
bucket = chosenBucket,
entity = player,
rodStack = player.mainHandStack // Crab, you should probably parse in the rod item connected to the bobber so we can check enchants in spawn conditions
)
val result = spawner.run(spawnCause, world as ServerWorld, pos.toBlockPos())
if (result == null) {
// This has a chance to fail, if the position has no suitability for a fishing context
// it could also just be a miss which
// means two attempts to spawn in the same location can have differing results (which is expected for
// randomness).
player.sendMessage("Not even a nibble".red())
}
var spawnedPokemon: PokemonEntity? = null
val resultingSpawn = result?.get()
if (resultingSpawn is EntitySpawnResult) {
for (entity in resultingSpawn.entities) {
player.sendMessage(commandLang("spawnpokemonfrompool.success", entity.displayName).green())
//pokemon.uuid = it.uuid
hookedEntityID = entity.id
spawnedPokemon = (entity as PokemonEntity)
// if spawned pokemon is a magikarp then lift it up into the air and over the player
if (spawnedPokemon.pokemon.species.name.equals("magikarp", ignoreCase = true)) {
// Direction and position calculations as before
val rad = Math.toRadians(player.yaw.toDouble() + 180)
val behindDirection = Vec3d(-Math.sin(rad), 0.0, Math.cos(rad))
val targetPos = player.pos.add(behindDirection.multiply(2.0))
val diff = targetPos.subtract(entity.pos)
val distance = diff.horizontalLength()
// Simple empirical mapping of distance to launch angle and initial velocity
val angle = when {
distance < 5 -> 60 // Closer targets, higher arc
distance < 10 -> 45 // Moderate distance, moderate arc
else -> 30 // Farther targets, lower arc
}
// Adjust velocity based on distance and angle
// These are placeholder values; you'll need to adjust based on testing
val velocityMultiplier = when {
distance < 5 -> 0.3
distance < 10 -> 0.5
distance < 20 -> .8
else -> 1.2
}
val velocityX = diff.x / distance * velocityMultiplier
val velocityZ = diff.z / distance * velocityMultiplier
// Calculate Y velocity component based on chosen angle, simplified
val velocityY = when {
distance < 5 -> 0.4
distance < 10 -> 0.5
distance < 20 -> 0.8
else -> 0.9
}
val tossVelocity = Vec3d(velocityX, velocityY, velocityZ)
entity.setVelocity(tossVelocity)
}
}
}
// What if it isn't an entity though
hookedEntity = world.getEntityById(hookedEntityID!!)
//val spawnedPokemon = spawnAction.entity
if (spawnedPokemon != null) {
BattleBuilder.pve((player as ServerPlayerEntity), spawnedPokemon).ifErrored { it.sendTo(player) { it.red() } }
}
}
}
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.entity.pokemon
import com.cobblemon.mod.common.*
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.CobblemonNetwork.sendPacketToServer
import com.cobblemon.mod.common.api.drop.DropTable
import com.cobblemon.mod.common.api.entity.Despawner
import com.cobblemon.mod.common.api.events.CobblemonEvents
@@ -33,7 +32,6 @@ import com.cobblemon.mod.common.api.types.ElementalTypes.FIRE
import com.cobblemon.mod.common.battles.BagItems
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.block.entity.PokemonPastureBlockEntity
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.Poseable
@@ -46,7 +44,6 @@ import com.cobblemon.mod.common.net.messages.client.animation.PlayPoseableAnimat
import com.cobblemon.mod.common.net.messages.client.sound.UnvalidatedPlaySoundS2CPacket
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokemonPacket
import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
import com.cobblemon.mod.common.net.messages.server.BattleChallengePacket
import com.cobblemon.mod.common.net.serverhandling.storage.SendOutPokemonHandler.SEND_OUT_DURATION
import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.pokemon.Pokemon
@@ -132,7 +129,6 @@ open class PokemonEntity(
@JvmStatic val HIDE_LABEL = DataTracker.registerData(PokemonEntity::class.java, TrackedDataHandlerRegistry.BOOLEAN)
@JvmStatic val UNBATTLEABLE = DataTracker.registerData(PokemonEntity::class.java, TrackedDataHandlerRegistry.BOOLEAN)
@JvmStatic val COUNTS_TOWARDS_SPAWN_CAP = DataTracker.registerData(PokemonEntity::class.java, TrackedDataHandlerRegistry.BOOLEAN)
@JvmStatic val SPAWN_DIRECTION = DataTracker.registerData(PokemonEntity::class.java, TrackedDataHandlerRegistry.FLOAT)
const val BATTLE_LOCK = "battle"
@@ -236,7 +232,6 @@ open class PokemonEntity(
dataTracker.startTracking(LABEL_LEVEL, 1)
dataTracker.startTracking(HIDE_LABEL, false)
dataTracker.startTracking(UNBATTLEABLE, false)
dataTracker.startTracking(SPAWN_DIRECTION, world.random.nextFloat() * 360F)
}
override fun onTrackedDataSet(data: TrackedData<*>) {
@@ -304,13 +299,6 @@ open class PokemonEntity(
this.updateEyeHeight()
}
if (ticksLived <= 20) {
clearPositionTarget()
val spawnDirection = dataTracker.get(SPAWN_DIRECTION)
setBodyYaw(spawnDirection)
prevBodyYaw = spawnDirection
}
if (this.tethering != null && !this.tethering!!.box.contains(this.x, this.y, this.z)) {
this.tethering = null
this.pokemon.recall()
@@ -836,7 +824,7 @@ open class PokemonEntity(
player.sendMessage(lang("held_item.already_holding", this.pokemon.getDisplayName(), stack.name))
return true
}
val returned = this.pokemon.swapHeldItem(stack = stack, decrement = !player.isCreative)
val returned = this.pokemon.swapHeldItem(stack, !player.isCreative)
val text = when {
giving.isEmpty -> lang("held_item.take", returned.name, this.pokemon.getDisplayName())
returned.isEmpty -> lang("held_item.give", this.pokemon.getDisplayName(), giving.name)
@@ -1040,21 +1028,6 @@ open class PokemonEntity(
dataTracker.set(NICKNAME_VISIBLE, visible)
}
/**
* Attempts to force initiate a battle with this Pokémon.
*
* @param player The player to attempt a battle with.
* @return Whether the battle was successfully started.
*/
fun forceBattle(player: PlayerEntity): Boolean {
if (!canBattle(player)) return false
if (CobblemonClient.storage.myParty.isEmpty()) return false
val selectedPokemon = CobblemonClient.storage.myParty.get(CobblemonClient.storage.selectedSlot) ?: return false
if (selectedPokemon.isFainted()) return false
sendPacketToServer(BattleChallengePacket(this.id, selectedPokemon.uuid))
return true
}
/**
* In the context of a Pokémon entity this checks if the Pokémon is currently set to displaying its nickname.
*
@@ -142,10 +142,10 @@ object CobblemonItemGroups {
entries.add(CobblemonItems.PLUME_FOSSIL)
entries.add(CobblemonItems.JAW_FOSSIL)
entries.add(CobblemonItems.SAIL_FOSSIL)
entries.add(CobblemonItems.FOSSILIZED_BIRD)
entries.add(CobblemonItems.FOSSILIZED_FISH)
entries.add(CobblemonItems.FOSSILIZED_DRAKE)
entries.add(CobblemonItems.FOSSILIZED_DINO)
entries.add(CobblemonItems.BIRD_FOSSIL)
entries.add(CobblemonItems.FISH_FOSSIL)
entries.add(CobblemonItems.DRAKE_FOSSIL)
entries.add(CobblemonItems.DINO_FOSSIL)
entries.add(CobblemonItems.TUMBLESTONE)
entries.add(CobblemonItems.BLACK_TUMBLESTONE)
@@ -179,37 +179,6 @@ object CobblemonItemGroups {
entries.add(CobblemonItems.SUSPICIOUS_SHERD)
entries.add(CobblemonItems.AUTOMATON_ARMOR_TRIM_SMITHING_TEMPLATE)
entries.add(CobblemonItems.RELIC_COIN)
entries.add(CobblemonItems.RELIC_COIN_POUCH)
entries.add(CobblemonItems.RELIC_COIN_SACK)
entries.add(CobblemonItems.GILDED_CHEST)
entries.add(CobblemonItems.YELLOW_GILDED_CHEST)
entries.add(CobblemonItems.GREEN_GILDED_CHEST)
entries.add(CobblemonItems.BLUE_GILDED_CHEST)
entries.add(CobblemonItems.PINK_GILDED_CHEST)
entries.add(CobblemonItems.BLACK_GILDED_CHEST)
entries.add(CobblemonItems.WHITE_GILDED_CHEST)
entries.add(CobblemonItems.GIMMIGHOUL_CHEST)
entries.add(CobblemonItems.NORMAL_GEM)
entries.add(CobblemonItems.FIRE_GEM)
entries.add(CobblemonItems.WATER_GEM)
entries.add(CobblemonItems.GRASS_GEM)
entries.add(CobblemonItems.ELECTRIC_GEM)
entries.add(CobblemonItems.ICE_GEM)
entries.add(CobblemonItems.FIGHTING_GEM)
entries.add(CobblemonItems.POISON_GEM)
entries.add(CobblemonItems.GROUND_GEM)
entries.add(CobblemonItems.FLYING_GEM)
entries.add(CobblemonItems.PSYCHIC_GEM)
entries.add(CobblemonItems.BUG_GEM)
entries.add(CobblemonItems.ROCK_GEM)
entries.add(CobblemonItems.GHOST_GEM)
entries.add(CobblemonItems.DRAGON_GEM)
entries.add(CobblemonItems.DARK_GEM)
entries.add(CobblemonItems.STEEL_GEM)
entries.add(CobblemonItems.FAIRY_GEM)
}
private fun blockEntries(displayContext: DisplayContext, entries: Entries) {
@@ -219,18 +188,6 @@ object CobblemonItemGroups {
entries.add(CobblemonItems.PC)
entries.add(CobblemonItems.HEALING_MACHINE)
entries.add(CobblemonItems.PASTURE)
entries.add(CobblemonItems.GILDED_CHEST)
entries.add(CobblemonItems.YELLOW_GILDED_CHEST)
entries.add(CobblemonItems.GREEN_GILDED_CHEST)
entries.add(CobblemonItems.BLUE_GILDED_CHEST)
entries.add(CobblemonItems.PINK_GILDED_CHEST)
entries.add(CobblemonItems.BLACK_GILDED_CHEST)
entries.add(CobblemonItems.WHITE_GILDED_CHEST)
entries.add(CobblemonItems.GIMMIGHOUL_CHEST)
entries.add(CobblemonItems.RELIC_COIN_POUCH)
entries.add(CobblemonItems.RELIC_COIN_SACK)
entries.add(CobblemonItems.APRICORN_LOG)
entries.add(CobblemonItems.APRICORN_WOOD)
entries.add(CobblemonItems.STRIPPED_APRICORN_LOG)
@@ -274,6 +231,7 @@ object CobblemonItemGroups {
entries.add(CobblemonItems.DEEPSLATE_THUNDER_STONE_ORE)
entries.add(CobblemonItems.WATER_STONE_ORE)
entries.add(CobblemonItems.DEEPSLATE_WATER_STONE_ORE)
entries.add(CobblemonItems.DYNITE_ORE)
}
private fun consumableEntries(displayContext: DisplayContext, entries: Entries) {
@@ -320,13 +278,6 @@ object CobblemonItemGroups {
entries.add(CobblemonItems.DIRE_HIT)
entries.add(CobblemonItems.GUARD_SPEC)
entries.add(CobblemonItems.HEALTH_FEATHER)
entries.add(CobblemonItems.MUSCLE_FEATHER)
entries.add(CobblemonItems.RESIST_FEATHER)
entries.add(CobblemonItems.GENIUS_FEATHER)
entries.add(CobblemonItems.CLEVER_FEATHER)
entries.add(CobblemonItems.SWIFT_FEATHER)
entries.add(CobblemonItems.HP_UP)
entries.add(CobblemonItems.PROTEIN)
entries.add(CobblemonItems.IRON)
@@ -474,36 +425,18 @@ object CobblemonItemGroups {
entries.add(CobblemonItems.TWISTED_SPOON)
entries.add(CobblemonItems.WHITE_HERB)
entries.add(CobblemonItems.WISE_GLASSES)
entries.add(CobblemonItems.NORMAL_GEM)
entries.add(CobblemonItems.FIRE_GEM)
entries.add(CobblemonItems.WATER_GEM)
entries.add(CobblemonItems.GRASS_GEM)
entries.add(CobblemonItems.ELECTRIC_GEM)
entries.add(CobblemonItems.ICE_GEM)
entries.add(CobblemonItems.FIGHTING_GEM)
entries.add(CobblemonItems.POISON_GEM)
entries.add(CobblemonItems.GROUND_GEM)
entries.add(CobblemonItems.FLYING_GEM)
entries.add(CobblemonItems.PSYCHIC_GEM)
entries.add(CobblemonItems.BUG_GEM)
entries.add(CobblemonItems.ROCK_GEM)
entries.add(CobblemonItems.GHOST_GEM)
entries.add(CobblemonItems.DRAGON_GEM)
entries.add(CobblemonItems.DARK_GEM)
entries.add(CobblemonItems.STEEL_GEM)
entries.add(CobblemonItems.FAIRY_GEM)
}
private fun pokeballentries(displayContext: DisplayContext, entries: Entries) {
CobblemonItems.pokeBalls.forEach(entries::add)
entries.add(CobblemonItems.POKEROD)
}
private fun foodInjections(injector: Injector) {
injector.putLast(CobblemonItems.ROASTED_LEEK)
injector.putAfter(CobblemonItems.LEEK_AND_POTATO_STEW, CobblemonItems.ROASTED_LEEK)
injector.putAfter(CobblemonItems.BRAISED_VIVICHOKE, CobblemonItems.LEEK_AND_POTATO_STEW)
injector.putAfter(CobblemonItems.VIVICHOKE_DIP, CobblemonItems.BRAISED_VIVICHOKE)
injector.putLast(CobblemonItems.LEEK_AND_POTATO_STEW)
injector.putLast(CobblemonItems.BRAISED_VIVICHOKE)
injector.putLast(CobblemonItems.VIVICHOKE_DIP)
}
private fun toolsAndUtilitiesInjections(injector: Injector) {
@@ -1,57 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.item.interactive
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.item.PokemonSelectingItem
import com.cobblemon.mod.common.api.pokemon.stats.Stat
import com.cobblemon.mod.common.item.CobblemonItem
import com.cobblemon.mod.common.pokemon.EVs
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.ItemStack
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.sound.SoundCategory
import net.minecraft.util.Hand
import net.minecraft.util.TypedActionResult
import net.minecraft.world.World
class FeatherItem(val stat: Stat) : CobblemonItem(Settings()), PokemonSelectingItem {
companion object {
const val EV_YIELD = 1
}
override val bagItem = null
override fun canUseOnPokemon(pokemon: Pokemon) = pokemon.evs.getOrDefault(stat) < EVs.MAX_STAT_VALUE
override fun applyToPokemon(
player: ServerPlayerEntity,
stack: ItemStack,
pokemon: Pokemon
): TypedActionResult<ItemStack> {
val evsGained = pokemon.evs.add(stat, EV_YIELD)
return if (evsGained > 0) {
player.playSound(CobblemonSounds.MEDICINE_FEATHER_USE, SoundCategory.PLAYERS, 1F, 1F)
if (!player.isCreative) {
stack.decrement(1)
}
TypedActionResult.success(stack)
} else {
TypedActionResult.fail(stack)
}
}
override fun use(world: World, user: PlayerEntity, hand: Hand): TypedActionResult<ItemStack> {
if (user is ServerPlayerEntity) {
return use(user, user.getStackInHand(hand))
}
return TypedActionResult.success(user.getStackInHand(hand))
}
}
@@ -0,0 +1,112 @@
/*
* 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/.
*/
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.cobblemon.mod.common.item
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity
import com.cobblemon.mod.common.item.CobblemonItem
import net.minecraft.enchantment.EnchantmentHelper
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.FishingRodItem
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.item.Item.Settings
import net.minecraft.entity.projectile.FishingBobberEntity
import net.minecraft.item.Items
import net.minecraft.sound.SoundCategory
import net.minecraft.sound.SoundEvents
import net.minecraft.stat.Stats
import net.minecraft.util.Hand
import net.minecraft.util.TypedActionResult
import net.minecraft.world.World
import net.minecraft.world.event.GameEvent
class PokerodItem(settings: Settings?) : FishingRodItem(settings) {
override fun use(world: World, user: PlayerEntity, hand: Hand): TypedActionResult<ItemStack> {
val itemStack = user.getStackInHand(hand)
val i: Int
if (user.fishHook != null) { // if the bobber is out yet
if (!world.isClient) {
i = user.fishHook!!.use(itemStack)
itemStack.damage(i, user) { p: PlayerEntity -> p.sendToolBreakStatus(hand) }
}
world.playSound(null as PlayerEntity?, user.x, user.y, user.z, SoundEvents.ENTITY_FISHING_BOBBER_RETRIEVE, SoundCategory.NEUTRAL, 1.0f, 0.4f / (world.getRandom().nextFloat() * 0.4f + 0.8f))
user.emitGameEvent(GameEvent.ITEM_INTERACT_FINISH)
} else { // if the bobber is not out yet
world.playSound(null as PlayerEntity?, user.x, user.y, user.z, SoundEvents.ENTITY_FISHING_BOBBER_THROW, SoundCategory.NEUTRAL, 0.5f, 0.4f / (world.getRandom().nextFloat() * 0.4f + 0.8f))
if (!world.isClient) {
i = EnchantmentHelper.getLure(itemStack)
val j = EnchantmentHelper.getLuckOfTheSea(itemStack)
world.spawnEntity(PokeRodFishingBobberEntity(user, world, j, i))
}
user.incrementStat(Stats.USED.getOrCreateStat(this))
user.emitGameEvent(GameEvent.ITEM_INTERACT_START)
}
return TypedActionResult.success(itemStack, world.isClient())
}
// todo Round 2
/*override fun use(world: World, user: PlayerEntity, hand: Hand): TypedActionResult<ItemStack> {
val itemStack = user.getStackInHand(hand)
// Play the throw sound
world.playSound(null as PlayerEntity?, user.x, user.y, user.z, SoundEvents.ENTITY_FISHING_BOBBER_THROW, SoundCategory.NEUTRAL, 0.5f, 0.4f / (world.getRandom().nextFloat() * 0.4f + 0.8f))
// Spawn the FishingBobberEntity directly without checking for an existing one
if (!world.isClient) {
val i = EnchantmentHelper.getLure(itemStack)
val j = EnchantmentHelper.getLuckOfTheSea(itemStack)
world.spawnEntity(PokeBobberEntity(user, world, j, i))
}
// Record the usage of the item
user.incrementStat(Stats.USED.getOrCreateStat(this))
user.emitGameEvent(GameEvent.ITEM_INTERACT_START)
return TypedActionResult.success(itemStack, world.isClient())
}*/
// todo Round 3 Best so far
/*override fun use(world: World, player: PlayerEntity, hand: Hand): TypedActionResult<ItemStack> {
if (!world.isClient) {
val itemStack = player.getStackInHand(hand)
// Calculate initial position and velocity for PokeBobberEntity
val currentPose = player.pose
val eyeHeight = player.getEyeHeight(currentPose)
val spawnPos = player.pos.add(0.0, eyeHeight.toDouble(), 0.0)
val direction = player.getRotationVec(1.0f)
val velocity = direction.multiply(1.5)
System.out.println("Spawn Position: " + spawnPos);
System.out.println("Velocity: " + velocity);
// Create and spawn PokeBobberEntity
val pokeBobber = PokeRodFishingBobberEntity(player, world, 0, 0)
pokeBobber.setPos(spawnPos.x, spawnPos.y, spawnPos.z)
pokeBobber.setVelocity(velocity.x, velocity.y, velocity.z)
//pokeBobber.use(ItemStack(CobblemonItems.POKEROD))
world.spawnEntity(pokeBobber)
//pokeBobber.use(ItemStack(Items.FISHING_ROD))
pokeBobber.use(itemStack)
}
return TypedActionResult.success(player.getStackInHand(hand))
}*/
override fun getEnchantability(): Int {
return 1
}
}
@@ -0,0 +1,9 @@
package com.cobblemon.mod.common.loot
import com.cobblemon.mod.common.util.cobblemonResource
object CobblemonLootTables {
val FALLING_STAR = cobblemonResource("entities/fallingstar")
}
@@ -16,13 +16,9 @@ import com.cobblemon.mod.common.api.net.Encodable
import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.api.pokemon.Natures
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeature
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.status.Statuses
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.net.IntSize
import com.cobblemon.mod.common.net.messages.client.pokemon.update.SpeciesFeatureUpdatePacket
import com.cobblemon.mod.common.pokemon.*
import com.cobblemon.mod.common.pokemon.activestate.PokemonState
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
@@ -75,8 +71,6 @@ class PokemonDTO : Encodable, Decodable {
var dmaxLevel = 0
var gmaxFactor = false
var tradeable = true
// var features: List<SynchronizedSpeciesFeature> = emptyList()
lateinit var featuresBuffer: PacketByteBuf
var originalTrainerType: OriginalTrainerType = OriginalTrainerType.NONE
var originalTrainer: String? = null
var originalTrainerName: String? = null
@@ -114,15 +108,6 @@ class PokemonDTO : Encodable, Decodable {
this.dmaxLevel = pokemon.dmaxLevel
this.gmaxFactor = pokemon.gmaxFactor
this.tradeable = pokemon.tradeable
this.featuresBuffer = PacketByteBuf(Unpooled.buffer())
val visibleFeatures = pokemon.features
.filterIsInstance<SynchronizedSpeciesFeature>()
.filter { (SpeciesFeatures.getFeature(it.name)!! as SynchronizedSpeciesFeatureProvider<*>).visible }
featuresBuffer.writeCollection(visibleFeatures) { _, value ->
featuresBuffer.writeString(value.name)
value.encode(featuresBuffer)
}
this.originalTrainerType = pokemon.originalTrainerType
this.originalTrainer = pokemon.originalTrainer
this.originalTrainerName = pokemon.originalTrainerName
@@ -163,10 +148,6 @@ class PokemonDTO : Encodable, Decodable {
buffer.writeInt(dmaxLevel)
buffer.writeBoolean(gmaxFactor)
buffer.writeBoolean(tradeable)
val featureByteCount = featuresBuffer.readableBytes()
buffer.writeSizedInt(IntSize.U_SHORT, featureByteCount)
buffer.writeBytes(featuresBuffer)
featuresBuffer.release()
buffer.writeString(originalTrainerType.name)
buffer.writeNullable(originalTrainer) { _, v -> buffer.writeString(v) }
buffer.writeNullable(originalTrainerName) { _, v -> buffer.writeString(v) }
@@ -208,9 +189,6 @@ class PokemonDTO : Encodable, Decodable {
dmaxLevel = buffer.readInt()
gmaxFactor = buffer.readBoolean()
tradeable = buffer.readBoolean()
val featureBytesToRead = buffer.readSizedInt(IntSize.U_SHORT)
featuresBuffer = PacketByteBuf(buffer.readBytes(featureBytesToRead))
originalTrainerType = OriginalTrainerType.valueOf(buffer.readString())
originalTrainer = buffer.readNullable { buffer.readString() }
originalTrainerName = buffer.readNullable { buffer.readString() }
@@ -226,6 +204,7 @@ class PokemonDTO : Encodable, Decodable {
it.experience = experience
it.level = level
it.setFriendship(friendship)
it.currentHealth = currentHealth
it.gender = gender
ivs.forEach { stat ->
it.setIV(stat.key, stat.value)
@@ -233,7 +212,6 @@ class PokemonDTO : Encodable, Decodable {
evs.forEach { stat ->
it.setEV(stat.key, stat.value)
}
it.currentHealth = currentHealth
it.moveSet.clear()
for (move in moveSet) {
it.moveSet.add(move)
@@ -263,17 +241,6 @@ class PokemonDTO : Encodable, Decodable {
it.dmaxLevel = dmaxLevel
it.gmaxFactor = gmaxFactor
it.tradeable = tradeable
repeat(times = featuresBuffer.readSizedInt(IntSize.U_BYTE)) { _ ->
val species = PokemonSpecies.getByIdentifier(this.species)!!
val speciesFeatureName = featuresBuffer.readString()
val featureProviders = SpeciesFeatures
.getFeaturesFor(species)
.filterIsInstance<SynchronizedSpeciesFeatureProvider<*>>()
val feature = featureProviders.firstNotNullOfOrNull { it(featuresBuffer, speciesFeatureName) } as? SynchronizedSpeciesFeature
?: throw IllegalArgumentException("Couldn't find a feature provider to deserialize this feature. Something's wrong.")
it.features.removeIf { it.name == feature.name }
it.features.add(feature)
}
when (originalTrainerType)
{
OriginalTrainerType.NONE -> {
@@ -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.net.messages.client.data
import com.cobblemon.mod.common.api.pokemon.feature.GlobalSpeciesFeatures
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeatureProvider
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.PacketByteBuf
/**
* Syncs a species feature provider that was registered under [GlobalSpeciesFeatures].
*
* @author Hiroku
* @since November 13th, 2023
*/
class GlobalSpeciesFeatureSyncPacket(speciesFeatures: Map<String, SpeciesFeatureProvider<*>>) : SpeciesFeatureSyncPacket(speciesFeatures) {
override val id = ID
override fun synchronizeDecoded(entries: Collection<Map.Entry<String, SynchronizedSpeciesFeatureProvider<*>>>) = GlobalSpeciesFeatures.loadOnClient(entries)
companion object {
val ID = cobblemonResource("global_species_feature_sync")
fun decode(buffer: PacketByteBuf) = GlobalSpeciesFeatureSyncPacket(emptyMap()).apply { decodeBuffer(buffer) }
}
}
@@ -1,48 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.net.messages.client.data
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatureAssignments
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.PacketByteBuf
import net.minecraft.util.Identifier
/**
* A registry sync packet for the [SpeciesFeatureAssignments] registry.
*
* @author Hiroku
* @since November 13th, 2023
*/
class SpeciesFeatureAssignmentSyncPacket(
data: Map<Identifier, MutableSet<String>>
) : DataRegistrySyncPacket<Map.Entry<Identifier, MutableSet<String>>, SpeciesFeatureAssignmentSyncPacket>(data.entries) {
override val id = ID
override fun decodeEntry(buffer: PacketByteBuf): Map.Entry<Identifier, MutableSet<String>> {
val key = buffer.readIdentifier()
val assignments = buffer.readList { buffer.readString() }.toMutableSet()
return object : Map.Entry<Identifier, MutableSet<String>> {
override val key = key
override val value = assignments
}
}
override fun encodeEntry(buffer: PacketByteBuf, entry: Map.Entry<Identifier, MutableSet<String>>) {
buffer.writeIdentifier(entry.key)
buffer.writeCollection(entry.value) { _, value -> buffer.writeString(value) }
}
override fun synchronizeDecoded(entries: Collection<Map.Entry<Identifier, MutableSet<String>>>) {
SpeciesFeatureAssignments.loadOnClient(entries.associate { it.toPair() })
}
companion object {
val ID = cobblemonResource("species_feature_assignment_sync")
fun decode(buffer: PacketByteBuf) = SpeciesFeatureAssignmentSyncPacket(emptyMap()).apply { decodeBuffer(buffer) }
}
}
@@ -1,68 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.net.messages.client.data
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeatureProvider
import net.minecraft.network.PacketByteBuf
/**
* Base class for a registry sync packet that synchronizes [SynchronizedSpeciesFeatureProvider]s.
*
* @author Hiroku
* @since November 13th, 2023
*/
abstract class SpeciesFeatureSyncPacket(
speciesFeatureProviders: Map<String, SpeciesFeatureProvider<*>>
) : DataRegistrySyncPacket<Map.Entry<String, SynchronizedSpeciesFeatureProvider<*>>, SpeciesFeatureSyncPacket>(
speciesFeatureProviders.entries.filterIsInstance<Map.Entry<String, SynchronizedSpeciesFeatureProvider<*>>>().filter { it.value.visible }
) {
override fun encodeEntry(buffer: PacketByteBuf, entry: Map.Entry<String, SynchronizedSpeciesFeatureProvider<*>>) {
val typeName = SpeciesFeatures.types.entries.find { it.value.isInstance(entry.value) }?.key
val value = entry.value
if (typeName == null) {
buffer.writeBoolean(false)
return
} else {
buffer.writeBoolean(true)
}
buffer.writeString(entry.key)
buffer.writeString(typeName)
value.encode(buffer)
}
override fun decodeEntry(buffer: PacketByteBuf): Map.Entry<String, SynchronizedSpeciesFeatureProvider<*>>? {
if (!buffer.readBoolean()) {
return null
}
val name = buffer.readString()
val typeName = buffer.readString()
val typeClass = SpeciesFeatures.types[typeName]
?: throw IllegalStateException(
"""
A custom species feature provider, $typeName with encoding implementations was registered on the server and
not the client, and therefore cannot be synced. Remove the implementation or install it
on the client.
""".trimIndent()
)
val instance = typeClass.getConstructor().newInstance()
if (instance !is SynchronizedSpeciesFeatureProvider) {
throw IllegalStateException("Somehow a non-SynchronizedSpeciesFeatureProvider was sent to the client. Version mismatch?")
} else {
instance.decode(buffer)
}
return object : Map.Entry<String, SynchronizedSpeciesFeatureProvider<*>> {
override val key: String = name
override val value: SynchronizedSpeciesFeatureProvider<*> = instance
}
}
}
@@ -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.net.messages.client.data
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeatureProvider
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.PacketByteBuf
import net.minecraft.util.Identifier
/**
* Syncs a species feature provider that was registered under [SpeciesFeatures].
*
* @author Hiroku
* @since November 13th, 2023
*/
class StandardSpeciesFeatureSyncPacket(providers: Map<String, SpeciesFeatureProvider<*>>) : SpeciesFeatureSyncPacket(providers) {
override val id: Identifier = ID
override fun synchronizeDecoded(entries: Collection<Map.Entry<String, SynchronizedSpeciesFeatureProvider<*>>>) = SpeciesFeatures.loadOnClient(entries)
companion object {
val ID = cobblemonResource("standard_species_feature_sync")
fun decode(buffer: PacketByteBuf) = StandardSpeciesFeatureSyncPacket(emptyMap()).apply { decodeBuffer(buffer) }
}
}
@@ -1,53 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.net.messages.client.pokemon.update
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeature
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeatureProvider
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.PacketByteBuf
import net.minecraft.util.Identifier
/**
* Updates the state of a particular [SynchronizedSpeciesFeature].
*
* @author Hiroku
* @since November 13th, 2023
*/
class SpeciesFeatureUpdatePacket(pokemon: () -> Pokemon, val species: Identifier, speciesFeature: SynchronizedSpeciesFeature) : SingleUpdatePacket<SynchronizedSpeciesFeature, SpeciesFeatureUpdatePacket>(pokemon, speciesFeature) {
companion object {
val ID = cobblemonResource("species_feature_update")
fun decode(buffer: PacketByteBuf): SpeciesFeatureUpdatePacket {
val pokemon = decodePokemon(buffer)
val speciesIdentifier = buffer.readIdentifier()
val species = PokemonSpecies.getByIdentifier(speciesIdentifier)
?: throw IllegalStateException("Pokémon unable to be found during species feature update packet: $speciesIdentifier")
val speciesFeatureName = buffer.readString()
val featureProviders = SpeciesFeatures.getFeaturesFor(species).filterIsInstance<SynchronizedSpeciesFeatureProvider<*>>()
val feature = featureProviders.firstNotNullOfOrNull { it(buffer, speciesFeatureName) } as? SynchronizedSpeciesFeature
?: throw IllegalArgumentException("Couldn't find a feature provider to deserialize this feature. Something's wrong.")
return SpeciesFeatureUpdatePacket(pokemon, speciesIdentifier, feature)
}
}
override val id = ID
override fun encodeValue(buffer: PacketByteBuf) {
buffer.writeIdentifier(species)
buffer.writeString(value.name)
value.encode(buffer)
}
override fun set(pokemon: Pokemon, value: SynchronizedSpeciesFeature) {
pokemon.features.removeIf { it.name == value.name }
pokemon.features.add(value)
}
}
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokeball.PokeBall
import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.util.cobblemonResource
@@ -38,7 +39,6 @@ class SpawnPokemonPacket(
private val unbattlable: Boolean,
private val hideLabel: Boolean,
private val caughtBall: Identifier,
private val spawnYaw: Float,
vanillaSpawnPacket: EntitySpawnS2CPacket
) : SpawnExtraDataEntityPacket<SpawnPokemonPacket, PokemonEntity>(vanillaSpawnPacket) {
@@ -59,7 +59,6 @@ class SpawnPokemonPacket(
entity.dataTracker.get(PokemonEntity.UNBATTLEABLE),
entity.dataTracker.get(PokemonEntity.HIDE_LABEL),
entity.pokemon.caughtBall.name,
entity.dataTracker.get(PokemonEntity.SPAWN_DIRECTION),
vanillaSpawnPacket
)
@@ -78,7 +77,6 @@ class SpawnPokemonPacket(
buffer.writeBoolean(this.unbattlable)
buffer.writeBoolean(this.hideLabel)
buffer.writeIdentifier(this.caughtBall)
buffer.writeFloat(this.spawnYaw)
}
override fun applyData(entity: PokemonEntity) {
@@ -100,7 +98,6 @@ class SpawnPokemonPacket(
entity.dataTracker.set(PokemonEntity.POSE_TYPE, poseType)
entity.dataTracker.set(PokemonEntity.UNBATTLEABLE, unbattlable)
entity.dataTracker.set(PokemonEntity.HIDE_LABEL, hideLabel)
entity.dataTracker.set(PokemonEntity.SPAWN_DIRECTION, spawnYaw)
}
override fun checkType(entity: Entity): Boolean = entity is PokemonEntity
@@ -123,10 +120,8 @@ class SpawnPokemonPacket(
val unbattlable = buffer.readBoolean()
val hideLabel = buffer.readBoolean()
val caughtBall = buffer.readIdentifier()
val spawnAngle = buffer.readFloat()
val vanillaPacket = decodeVanillaPacket(buffer)
return SpawnPokemonPacket(ownerId, scaleModifier, species, form, aspects, battleId, phasingTargetId, beamModeEmitter, nickname, labelLevel, poseType, unbattlable, hideLabel, caughtBall, spawnAngle, vanillaPacket)
return SpawnPokemonPacket(ownerId, scaleModifier, species, form, aspects, battleId, phasingTargetId, beamModeEmitter, nickname, labelLevel, poseType, unbattlable, hideLabel, caughtBall, vanillaPacket)
}
}
@@ -1,32 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.net.messages.server.battle
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.PacketByteBuf
import java.util.UUID
class FleeBattlePacket(val battleId: UUID) : NetworkPacket<FleeBattlePacket> {
override val id = ID
override fun encode(buffer: PacketByteBuf) {
buffer.writeUuid(battleId)
}
companion object {
val ID = cobblemonResource("flee_battle")
fun decode(buffer: PacketByteBuf): FleeBattlePacket {
return FleeBattlePacket(buffer.readUuid())
}
}
}
@@ -1,25 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.net.serverhandling.battle
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.net.messages.server.battle.FleeBattlePacket
import com.cobblemon.mod.common.util.battleLang
import net.minecraft.server.MinecraftServer
import net.minecraft.server.network.ServerPlayerEntity
object FleeBattlePacketHandler : ServerNetworkPacketHandler<FleeBattlePacket> {
override fun handle(packet: FleeBattlePacket, server: MinecraftServer, player: ServerPlayerEntity) {
val battle = BattleRegistry.getBattle(packet.battleId) ?: return
player.sendMessage(battleLang("flee"))
battle.end()
}
}
@@ -18,10 +18,8 @@ import com.cobblemon.mod.common.api.abilities.Ability
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.CobblemonEvents.FRIENDSHIP_UPDATED
import com.cobblemon.mod.common.api.events.CobblemonEvents.HELD_ITEM_UPDATED
import com.cobblemon.mod.common.api.events.CobblemonEvents.POKEMON_FAINTED
import com.cobblemon.mod.common.api.events.pokemon.*
import com.cobblemon.mod.common.api.events.pokemon.interaction.HeldItemUpdatedEvent
import com.cobblemon.mod.common.api.moves.*
import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.api.pokemon.Natures
@@ -34,7 +32,6 @@ import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroup
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceSource
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeature
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeature
import com.cobblemon.mod.common.api.pokemon.friendship.FriendshipMutationCalculator
import com.cobblemon.mod.common.api.pokemon.labels.CobblemonPokemonLabels
import com.cobblemon.mod.common.api.pokemon.moves.LearnsetQuery
@@ -62,7 +59,6 @@ import com.cobblemon.mod.common.pokemon.evolution.CobblemonEvolutionProxy
import com.cobblemon.mod.common.pokemon.evolution.progress.DamageTakenEvolutionProgress
import com.cobblemon.mod.common.pokemon.evolution.progress.RecoilEvolutionProgress
import com.cobblemon.mod.common.pokemon.feature.SeasonFeatureHandler
import com.cobblemon.mod.common.pokemon.misc.GimmighoulStashHandler
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
import com.cobblemon.mod.common.pokemon.status.PersistentStatusContainer
@@ -113,11 +109,9 @@ open class Pokemon : ShowdownIdentifiable {
}
val quotient = clamp(currentHealth / hp.toFloat(), 0F, 1F)
field = value
if (!isClient) {
val newFeatures = SpeciesFeatures.getFeaturesFor(species).mapNotNull { it.invoke(this) }
features.clear()
features.addAll(newFeatures)
}
val newFeatures = SpeciesFeatures.getFeaturesFor(species).mapNotNull { it.invoke(this) }
features.clear()
features.addAll(newFeatures)
this.evolutionProxy.current().clear()
updateAspects()
updateForm()
@@ -259,7 +253,6 @@ open class Pokemon : ShowdownIdentifiable {
_friendship.emit(it.newFriendship)
}
}
var state: PokemonState = InactivePokemonState()
set(value) {
field = value
@@ -692,9 +685,7 @@ open class Pokemon : ShowdownIdentifiable {
}
this.heldItem = giving
this._heldItem.emit(giving)
CobblemonEvents.HELD_ITEM_POST.post(HeldItemEvent.Post(this, this.heldItem(), event.returning.copy(), event.decrement)) {
GimmighoulStashHandler.giveHeldItem(it)
}
CobblemonEvents.HELD_ITEM_POST.post(HeldItemEvent.Post(this, this.heldItem(), event.returning.copy(), event.decrement))
return event.returning
})
return stack
@@ -1420,14 +1411,11 @@ open class Pokemon : ShowdownIdentifiable {
storeCoordinates.get()?.run { sendPacketToPlayers(store.getObservingPlayers(), packet) }
}
fun <T> registerObservable(observable: SimpleObservable<T>, notifyPacket: ((T) -> PokemonUpdatePacket<*>?)? = null): SimpleObservable<T> {
fun <T> registerObservable(observable: SimpleObservable<T>, notifyPacket: ((T) -> PokemonUpdatePacket<*>)? = null): SimpleObservable<T> {
observables.add(observable)
observable.subscribe {
if (notifyPacket != null && storeCoordinates.get() != null) {
val packet = notifyPacket(it)
if (packet != null) {
notify(packet)
}
notify(notifyPacket(it))
}
anyChangeObservable.emit(this)
}
@@ -1517,13 +1505,7 @@ open class Pokemon : ShowdownIdentifiable {
private val _gmaxFactor = registerObservable(SimpleObservable<Boolean>()) { GmaxFactorUpdatePacket({ this }, it) }
private val _originalTrainerName = registerObservable(SimpleObservable<String?>()) { OriginalTrainerUpdatePacket({ this }, it) }
private val _features = registerObservable(SimpleObservable<SpeciesFeature>()) {
if (it is SynchronizedSpeciesFeature) {
SpeciesFeatureUpdatePacket({ this }, species.resourceIdentifier, it)
} else {
null
}
}
private val _features = registerObservable(SimpleObservable<SpeciesFeature>())
companion object {
/**
@@ -199,7 +199,6 @@ class Species : ClientDataSynchronizer<Species>, ShowdownIdentifiable {
buffer.writeCollection(this.pokedex) { pb, line -> pb.writeString(line) }
buffer.writeCollection(this.forms) { pb, form -> form.encode(pb) }
buffer.writeIdentifier(this.battleTheme)
buffer.writeCollection(this.features) { pb, feature -> pb.writeString(feature) }
buffer.writeNullable(this.lightingData) { pb, data ->
pb.writeInt(data.lightLevel)
pb.writeEnumConstant(data.liquidGlowMode)
@@ -227,8 +226,6 @@ class Species : ClientDataSynchronizer<Species>, ShowdownIdentifiable {
this.forms.clear()
this.forms += buffer.readList{ pb -> FormData().apply { decode(pb) } }.filterNotNull()
this.battleTheme = buffer.readIdentifier()
this.features.clear()
this.features += buffer.readList { pb -> pb.readString() }
this.lightingData = buffer.readNullable { pb -> LightingData(pb.readInt(), pb.readEnumConstant(LightingData.LiquidGlowMode::class.java)) }
this.initialize()
}
@@ -251,7 +248,6 @@ class Species : ClientDataSynchronizer<Species>, ShowdownIdentifiable {
// We only sync level up moves atm
|| this.moves.shouldSynchronize(other.moves)
|| other.battleTheme != this.battleTheme
|| other.features != this.features
}
/**

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