mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-20 22:26:24 -04:00
Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c74f01bd6d | ||
|
|
199a8ba675 | ||
|
|
556f92e4b0 | ||
|
|
4f395ca47f | ||
|
|
2a5a292386 | ||
|
|
e8a09f5c48 | ||
|
|
e82193cdfd | ||
|
|
87e7cdebf6 | ||
|
|
9ca84d852f |
@@ -36,6 +36,9 @@
|
||||
- Fixed friendship resetting to the default value when evolving a Pokémon.
|
||||
- Fixed a bunch of incompatibilities with NeoForge mods
|
||||
- Fixed a bug where wind charges hitting pasture blocks would recall all pokémon in it.
|
||||
- Home on the Range advancement shouldn't trigger when opening the Pokemon Menu (shift interact one, mr changelog guy)
|
||||
- Recipes using concrete should now work on NeoForge
|
||||
- Fixed saccharine hanging signs sometimes dropping their oak wood counterpart when being broken
|
||||
|
||||
### Developer
|
||||
|
||||
|
||||
@@ -37,16 +37,16 @@ public class ClientPacketListenerMixin {
|
||||
passengers.add(this.level.getEntity(passenger));
|
||||
}
|
||||
Arrays
|
||||
.stream(pokemon.getOccupiedSeats())
|
||||
.filter(x -> !passengers.contains(x))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(Entity::stopRiding);
|
||||
.stream(pokemon.getOccupiedSeats())
|
||||
.filter(x -> !passengers.contains(x))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(Entity::stopRiding);
|
||||
|
||||
var occupiedSeats = Arrays.asList(pokemon.getOccupiedSeats());
|
||||
passengers.stream()
|
||||
.filter(x -> !occupiedSeats.contains(x))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(x -> x.startRiding(pokemon, true));
|
||||
.filter(x -> !occupiedSeats.contains(x))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(x -> x.startRiding(pokemon, true));
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
@JvmField
|
||||
val SACCHARINE_WALL_SIGN = this.create("saccharine_wall_sign", CobblemonWallSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_SIGN), SACCHARINE_WOOD_TYPE))
|
||||
@JvmField
|
||||
val SACCHARINE_HANGING_SIGN = this.create("saccharine_hanging_sign", CobblemonHangingSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_WALL_HANGING_SIGN), SACCHARINE_WOOD_TYPE))
|
||||
val SACCHARINE_HANGING_SIGN = this.create("saccharine_hanging_sign", CobblemonHangingSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_HANGING_SIGN), SACCHARINE_WOOD_TYPE))
|
||||
@JvmField
|
||||
val SACCHARINE_WALL_HANGING_SIGN = this.create("saccharine_wall_hanging_sign", CobblemonWallHangingSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_HANGING_SIGN), SACCHARINE_WOOD_TYPE))
|
||||
@JvmField
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.cobblemon.mod.common.block.MintBlock
|
||||
import com.cobblemon.mod.common.block.MintBlock.MintType
|
||||
import com.cobblemon.mod.common.client.pokedex.PokedexType
|
||||
import com.cobblemon.mod.common.block.campfirepot.CampfirePotColor
|
||||
import com.cobblemon.mod.common.config.CobblemonConfig
|
||||
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
|
||||
import com.cobblemon.mod.common.item.*
|
||||
import com.cobblemon.mod.common.item.armor.CobblemonArmorTrims
|
||||
@@ -42,6 +43,7 @@ import com.cobblemon.mod.common.item.interactive.ability.AbilityChangeItem
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import com.cobblemon.mod.common.pokeball.PokeBall
|
||||
import com.cobblemon.mod.common.pokemon.IVs
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.core.Registry
|
||||
@@ -50,6 +52,7 @@ import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceKey
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.effect.MobEffectInstance
|
||||
import net.minecraft.world.effect.MobEffects
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
@@ -66,6 +69,7 @@ import net.minecraft.world.item.SignItem
|
||||
import net.minecraft.world.item.SmithingTemplateItem
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.Block
|
||||
import kotlin.math.ceil
|
||||
|
||||
@Suppress("unused", "SameParameterValue")
|
||||
object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<Item>>, Item>() {
|
||||
@@ -614,7 +618,11 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
|
||||
// Medicine
|
||||
@JvmField
|
||||
val RARE_CANDY = candyItem("rare_candy", Rarity.RARE) { _, pokemon -> pokemon.getExperienceToNextLevel() }
|
||||
val RARE_CANDY = candyItem("rare_candy", Rarity.RARE) { player, pokemon ->
|
||||
if (pokemon != null) return@candyItem pokemon.getExperienceToNextLevel()
|
||||
return@candyItem -1
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val EXPERIENCE_CANDY_XS = candyItem("exp_candy_xs") { _, _ -> CandyItem.DEFAULT_XS_CANDY_YIELD }
|
||||
@JvmField
|
||||
@@ -1476,7 +1484,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
return item
|
||||
}
|
||||
|
||||
private fun candyItem(name: String, rarity: Rarity = Rarity.COMMON, calculator: CandyItem.Calculator): CandyItem = this.create(name, CandyItem(rarity, calculator))
|
||||
private fun candyItem(name: String, rarity: Rarity = Rarity.COMMON, calculator: (ServerPlayer, Pokemon?) -> Int): CandyItem = this.create(name, CandyItem(rarity, calculator))
|
||||
|
||||
private fun pokerodItem(pokeRodId: ResourceLocation, rarity: Rarity = Rarity.COMMON): PokerodItem {
|
||||
val settings = Item.Properties().stacksTo(1).durability(256).rarity(rarity)
|
||||
|
||||
+6
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import net.minecraft.commands.CommandSourceStack
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
/**
|
||||
@@ -25,8 +26,13 @@ interface ExperienceSource {
|
||||
fun isInteraction() = this is CandyExperienceSource
|
||||
fun isCommand() = this is CommandExperienceSource
|
||||
fun isSidemod() = this is SidemodExperienceSource
|
||||
fun isMob() = this is MobExperienceSource
|
||||
}
|
||||
|
||||
open class MobExperienceSource(
|
||||
mob: LivingEntity,
|
||||
) : ExperienceSource
|
||||
|
||||
open class SidemodExperienceSource(
|
||||
val sidemodId: String
|
||||
) : ExperienceSource
|
||||
|
||||
-1
@@ -34,7 +34,6 @@ import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.writeNullableExpression
|
||||
import com.cobblemon.mod.common.util.writeRidingStats
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.player.LocalPlayer
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
@@ -344,6 +344,9 @@ class CobblemonConfig {
|
||||
@CobblemonConfigField(Category.Spawning, lang = "despawner_max_age_ticks", SERVER)
|
||||
var despawnerMaxAgeTicks = 3600
|
||||
|
||||
@CobblemonConfigField(Category.World, lang = "mob_experience_conversion_rate", SERVER)
|
||||
var mobExperienceConversionRate = 50.0
|
||||
|
||||
fun clone(): CobblemonConfig {
|
||||
val newConfig = CobblemonConfig()
|
||||
CobblemonConfig::class.memberProperties.forEach { property ->
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.cobblemon.mod.common.api.net.serializers.PoseTypeDataSerializer
|
||||
import com.cobblemon.mod.common.api.net.serializers.RideBoostsDataSerializer
|
||||
import com.cobblemon.mod.common.api.net.serializers.StringSetDataSerializer
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.MobExperienceSource
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.ChoiceSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.FlagSpeciesFeature
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
|
||||
@@ -1259,7 +1260,18 @@ open class PokemonEntity(
|
||||
|
||||
override fun doHurtTarget(target: Entity): Boolean {
|
||||
if (beamMode != 0) return false
|
||||
return super.doHurtTarget(target)
|
||||
val result = super.doHurtTarget(target)
|
||||
if (result && !target.isAlive && target is LivingEntity && !level().isClientSide) {
|
||||
val experience = target.getExperienceReward(level() as ServerLevel, this)
|
||||
val source = MobExperienceSource(mob = target)
|
||||
if (this.owner is ServerPlayer) {
|
||||
pokemon.addExperienceWithPlayer(this.owner as ServerPlayer, source, (experience * Cobblemon.config.mobExperienceConversionRate).toInt())
|
||||
}
|
||||
else {
|
||||
pokemon.addExperience(source, (experience * Cobblemon.config.mobExperienceConversionRate).toInt())
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override fun hurt(source: DamageSource, amount: Float): Boolean {
|
||||
|
||||
@@ -8,17 +8,24 @@
|
||||
|
||||
package com.cobblemon.mod.common.item.interactive
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.pokemon.interaction.ExperienceCandyUseEvent
|
||||
import com.cobblemon.mod.common.api.item.PokemonSelectingItem
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.CandyExperienceSource
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.item.CobblemonItem
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.InteractionResultHolder
|
||||
import net.minecraft.world.entity.ExperienceOrb
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.food.FoodProperties
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Rarity
|
||||
import net.minecraft.world.level.Level
|
||||
@@ -34,22 +41,59 @@ import net.minecraft.world.level.Level
|
||||
*/
|
||||
class CandyItem(
|
||||
val item_rarity: Rarity,
|
||||
val calculator: Calculator
|
||||
val expYield: (ServerPlayer, Pokemon?) -> Int
|
||||
) : CobblemonItem(Properties().apply {
|
||||
rarity(item_rarity)
|
||||
}), PokemonSelectingItem {
|
||||
food(FoodProperties.Builder()
|
||||
.alwaysEdible()
|
||||
.nutrition(0)
|
||||
.saturationModifier(0.0f)
|
||||
.build())
|
||||
}) {
|
||||
|
||||
override val bagItem = null
|
||||
override fun finishUsingItem(stack: ItemStack, level: Level, livingEntity: LivingEntity): ItemStack? {
|
||||
if (livingEntity !is Player) return super.finishUsingItem(stack, level, livingEntity)
|
||||
|
||||
override fun use(world: Level, user: Player, hand: InteractionHand): InteractionResultHolder<ItemStack> {
|
||||
if (user is ServerPlayer) {
|
||||
return use(user, user.getItemInHand(hand))
|
||||
/* Didn't find a good way to determine the XP needed until the beginning of the next level.
|
||||
* This works but is a little jank. Feel free to investigate a better solution.
|
||||
*/
|
||||
if (level.isClientSide && this == CobblemonItems.RARE_CANDY) {
|
||||
val volume = if (livingEntity.experienceLevel > 30) 1.0f else livingEntity.experienceLevel.toFloat() / 30.0f
|
||||
livingEntity.playSound(SoundEvents.PLAYER_LEVELUP, volume * 0.75f, 1.0f)
|
||||
}
|
||||
return InteractionResultHolder.success(user.getItemInHand(hand))
|
||||
|
||||
if (livingEntity !is ServerPlayer) return super.finishUsingItem(stack, level, livingEntity)
|
||||
if (this == CobblemonItems.RARE_CANDY) {
|
||||
livingEntity.setExperienceLevels(livingEntity.experienceLevel + 1)
|
||||
livingEntity.setExperiencePoints(0)
|
||||
}
|
||||
else {
|
||||
val expYield = expYield(livingEntity, null)
|
||||
val playerExperience = (expYield / Cobblemon.config.mobExperienceConversionRate).toInt().coerceAtLeast(1)
|
||||
ExperienceOrb.award(livingEntity.serverLevel(), livingEntity.position(), playerExperience)
|
||||
}
|
||||
return super.finishUsingItem(stack, level, livingEntity)
|
||||
}
|
||||
|
||||
override fun applyToPokemon(player: ServerPlayer, stack: ItemStack, pokemon: Pokemon): InteractionResultHolder<ItemStack>? {
|
||||
val experience = this.calculator.calculate(player, pokemon)
|
||||
override fun interactLivingEntity(
|
||||
stack: ItemStack,
|
||||
player: Player,
|
||||
interactionTarget: LivingEntity,
|
||||
usedHand: InteractionHand
|
||||
): InteractionResult {
|
||||
if (player.level().isClientSide) return InteractionResult.FAIL
|
||||
if (player.isCrouching) return InteractionResult.FAIL
|
||||
if (interactionTarget !is PokemonEntity) return InteractionResult.PASS
|
||||
if (interactionTarget.pokemon.getOwnerPlayer() != player) return InteractionResult.PASS
|
||||
return applyToPokemon(player as ServerPlayer, stack, interactionTarget.pokemon)?.result ?: InteractionResult.FAIL
|
||||
}
|
||||
|
||||
fun applyToPokemon(player: ServerPlayer, stack: ItemStack, pokemon: Pokemon): InteractionResultHolder<ItemStack>? {
|
||||
if (!pokemon.canLevelUpFurther()) {
|
||||
return InteractionResultHolder.fail(stack)
|
||||
}
|
||||
|
||||
val experience = expYield(player, pokemon)
|
||||
CobblemonEvents.EXPERIENCE_CANDY_USE_PRE.postThen(
|
||||
event = ExperienceCandyUseEvent.Pre(player, pokemon, this, experience, experience),
|
||||
ifSucceeded = { preEvent ->
|
||||
@@ -74,29 +118,6 @@ class CandyItem(
|
||||
return InteractionResultHolder.fail(stack)
|
||||
}
|
||||
|
||||
override fun canUseOnPokemon(stack: ItemStack, pokemon: Pokemon): Boolean {
|
||||
return pokemon.isPlayerOwned()
|
||||
}
|
||||
|
||||
/**
|
||||
* Functional interface responsible for resolving the experience a candy will yield.
|
||||
*
|
||||
* @author Licious
|
||||
* @since March 5th, 2022
|
||||
*/
|
||||
fun interface Calculator {
|
||||
|
||||
/**
|
||||
* Resolves the experience the [CandyItem] will give.
|
||||
*
|
||||
* @param player The [ServerPlayer] using the candy.
|
||||
* @param pokemon The [Pokemon] receiving experience.
|
||||
* @return The experience that will be received
|
||||
*/
|
||||
fun calculate(player: ServerPlayer, pokemon: Pokemon): Int
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val DEFAULT_XS_CANDY_YIELD = 100
|
||||
const val DEFAULT_S_CANDY_YIELD = 800
|
||||
|
||||
+2
-11
@@ -24,19 +24,10 @@ class ClientboundUpdateRidingStatePacket(
|
||||
override val id = ID
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
//We need to allow for encoding the data buffer instead of state for Flashback compat
|
||||
//Flashback needs to be able to call encode on the packet it gets, which only has data, not state yet.
|
||||
if (state == null && data == null) error("Expected state or data to be populated for encoding")
|
||||
if (state == null) error("Expected state to be populated for encoding")
|
||||
buffer.writeInt(entity)
|
||||
buffer.writeResourceLocation(behaviour)
|
||||
if (state != null) {
|
||||
state.encode(buffer)
|
||||
}
|
||||
else if (data != null) {
|
||||
buffer.writeBytes(data)
|
||||
//So the buffer can be read in the future
|
||||
data.resetReaderIndex()
|
||||
}
|
||||
state.encode(buffer)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.pokemon
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacketToPlayers
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
@@ -148,6 +149,7 @@ import net.minecraft.util.Mth.ceil
|
||||
import net.minecraft.util.Mth.clamp
|
||||
import net.minecraft.util.StringRepresentable
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.entity.ExperienceOrb
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.MobSpawnType
|
||||
import net.minecraft.world.entity.player.Player
|
||||
@@ -2016,6 +2018,12 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
}
|
||||
)
|
||||
|
||||
val player = getOwnerPlayer()
|
||||
if (player != null && player.inventory.getArmor(3).item == CobblemonItems.EXP_SHARE) {
|
||||
val playerExperience = (appliedXP / Cobblemon.config.mobExperienceConversionRate * Cobblemon.config.experienceShareMultiplier).toInt().coerceAtLeast(1)
|
||||
ExperienceOrb.award(player.serverLevel(), player.position(), playerExperience)
|
||||
}
|
||||
|
||||
experience += appliedXP
|
||||
// Bound is needed here as we can still be allowed to level up but go over the current cap
|
||||
var newLevel = experienceGroup.getLevel(experience).coerceAtMost(Cobblemon.config.maxPokemonLevel)
|
||||
|
||||
@@ -2621,6 +2621,8 @@
|
||||
"cobblemon.config.ui.infinite_ride_stamina.tooltip": "Whether rideable Pokémon have infinite stamina.",
|
||||
"cobblemon.config.ui.remember_riding_camera": "Remember Riding Camera",
|
||||
"cobblemon.config.ui.remember_riding_camera.tooltip": "Whether the camera mode will automatically switch to the last used camera mode when mounting a rideable Pokémon.",
|
||||
"cobblemon.config.ui.mob_experience_conversion_rate": "Mob Experience Conversion Rate",
|
||||
"cobblemon.config.ui.mob_experience_conversion_rate.tooltip": "The conversion rate for mob experience to pokemon experience when a Pokemon kills a mob.",
|
||||
|
||||
"cobblemon.config.ui.allow_starter_on_join": "Allow Starter on Join",
|
||||
"cobblemon.config.ui.prompt_starter_once_only": "Prompt Starter Once Only",
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
{
|
||||
"display": {
|
||||
"icon": {
|
||||
"id": "minecraft:shears"
|
||||
},
|
||||
"icon": {
|
||||
"id": "minecraft:shears"
|
||||
},
|
||||
"title": {
|
||||
"translate": "advancements.cobblemon.interact_with_pokemon"
|
||||
},
|
||||
"description": {
|
||||
"translate": "advancements.cobblemon.interact_with_pokemon.description"
|
||||
},
|
||||
"hidden": false
|
||||
"hidden": false
|
||||
},
|
||||
"parent": "cobblemon:use_pasture",
|
||||
"criteria": {
|
||||
"bucket_interactable_pokemon": {
|
||||
"conditions": {
|
||||
"player": {
|
||||
"flags": {
|
||||
"is_sneaking": false
|
||||
}
|
||||
},
|
||||
"entity": [
|
||||
{
|
||||
"condition": "minecraft:entity_properties",
|
||||
@@ -32,6 +37,11 @@
|
||||
},
|
||||
"shear_interactable_pokemon": {
|
||||
"conditions": {
|
||||
"player": {
|
||||
"flags": {
|
||||
"is_sneaking": false
|
||||
}
|
||||
},
|
||||
"entity": [
|
||||
{
|
||||
"condition": "minecraft:entity_properties",
|
||||
@@ -49,6 +59,11 @@
|
||||
},
|
||||
"bottle_interactable_pokemon": {
|
||||
"conditions": {
|
||||
"player": {
|
||||
"flags": {
|
||||
"is_sneaking": false
|
||||
}
|
||||
},
|
||||
"entity": [
|
||||
{
|
||||
"condition": "minecraft:entity_properties",
|
||||
@@ -66,6 +81,11 @@
|
||||
},
|
||||
"brush_interactable_pokemon": {
|
||||
"conditions": {
|
||||
"player": {
|
||||
"flags": {
|
||||
"is_sneaking": false
|
||||
}
|
||||
},
|
||||
"entity": [
|
||||
{
|
||||
"condition": "minecraft:entity_properties",
|
||||
@@ -83,6 +103,11 @@
|
||||
},
|
||||
"bonemeal_interactable_pokemon": {
|
||||
"conditions": {
|
||||
"player": {
|
||||
"flags": {
|
||||
"is_sneaking": false
|
||||
}
|
||||
},
|
||||
"entity": [
|
||||
{
|
||||
"condition": "minecraft:entity_properties",
|
||||
@@ -100,6 +125,11 @@
|
||||
},
|
||||
"bowl_interactable_pokemon": {
|
||||
"conditions": {
|
||||
"player": {
|
||||
"flags": {
|
||||
"is_sneaking": false
|
||||
}
|
||||
},
|
||||
"entity": [
|
||||
{
|
||||
"condition": "minecraft:entity_properties",
|
||||
@@ -116,6 +146,15 @@
|
||||
"trigger": "minecraft:player_interacted_with_entity"
|
||||
}
|
||||
},
|
||||
"requirements": [[ "bucket_interactable_pokemon", "shear_interactable_pokemon", "bottle_interactable_pokemon", "brush_interactable_pokemon", "bonemeal_interactable_pokemon", "bowl_interactable_pokemon" ]],
|
||||
"requirements": [
|
||||
[
|
||||
"bucket_interactable_pokemon",
|
||||
"shear_interactable_pokemon",
|
||||
"bottle_interactable_pokemon",
|
||||
"brush_interactable_pokemon",
|
||||
"bonemeal_interactable_pokemon",
|
||||
"bowl_interactable_pokemon"
|
||||
]
|
||||
],
|
||||
"sends_telemetry_event": false
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
"item": "cobblemon:green_mint_leaf"
|
||||
},
|
||||
"C": {
|
||||
"tag": "c:concrete"
|
||||
"tag": "c:concretes"
|
||||
},
|
||||
"D": {
|
||||
"tag": "c:gems/diamond"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"item": "cobblemon:pink_mint_leaf"
|
||||
},
|
||||
"C": {
|
||||
"tag": "c:concrete"
|
||||
"tag": "c:concretes"
|
||||
},
|
||||
"D": {
|
||||
"tag": "c:gems/diamond"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"item": "cobblemon:blue_mint_leaf"
|
||||
},
|
||||
"C": {
|
||||
"tag": "c:concrete"
|
||||
"tag": "c:concretes"
|
||||
},
|
||||
"D": {
|
||||
"tag": "c:gems/diamond"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"item": "cobblemon:red_mint_leaf"
|
||||
},
|
||||
"C": {
|
||||
"tag": "c:concrete"
|
||||
"tag": "c:concretes"
|
||||
},
|
||||
"D": {
|
||||
"tag": "c:gems/diamond"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"item": "cobblemon:cyan_mint_leaf"
|
||||
},
|
||||
"C": {
|
||||
"tag": "c:concrete"
|
||||
"tag": "c:concretes"
|
||||
},
|
||||
"D": {
|
||||
"tag": "c:gems/diamond"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"item": "cobblemon:white_mint_leaf"
|
||||
},
|
||||
"C": {
|
||||
"tag": "c:concrete"
|
||||
"tag": "c:concretes"
|
||||
},
|
||||
"D": {
|
||||
"tag": "c:gems/diamond"
|
||||
|
||||
@@ -38,7 +38,6 @@ repositories {
|
||||
maven("https://oss.sonatype.org/content/repositories/snapshots")
|
||||
maven(url = "https://api.modrinth.com/maven")
|
||||
maven(url = "https://maven.terraformersmc.com/")
|
||||
maven(url = "https://api.modrinth.com/maven")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -59,13 +58,6 @@ dependencies {
|
||||
|
||||
modImplementation(libs.bundles.fabric.integrations.implementation)
|
||||
modRuntimeOnly(libs.bundles.fabric.integrations.runtimeOnly)
|
||||
modImplementation("maven.modrinth:flashback:0.38.2-fabric,1.21.1")
|
||||
// Lattice (config)
|
||||
modImplementation("com.moulberry:lattice:1.2.18") {
|
||||
attributes {
|
||||
attribute(Attribute.of("earth.terrarium.cloche.modLoader", String::class.java), "fabric")
|
||||
}
|
||||
}
|
||||
|
||||
// modImplementation(libs.flywheelFabric)
|
||||
// include(libs.flywheelFabric)
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.fabric.mixin.compat;
|
||||
|
||||
import com.cobblemon.mod.common.duck.PlayerDuck;
|
||||
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateDriverInputPacket;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import com.moulberry.flashback.record.Recorder;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket;
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import org.joml.Vector3f;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(Recorder.class)
|
||||
public abstract class RecorderMixin {
|
||||
@Inject(method = "writeLocalData()V", at = @At(value = "INVOKE", target = "Lcom/moulberry/flashback/io/AsyncReplaySaver;writeGamePackets(Lnet/minecraft/network/codec/StreamCodec;Ljava/util/List;)V"))
|
||||
public void cobblemon$writeLocalData(
|
||||
CallbackInfo ci,
|
||||
@Local(name = "gamePackets") List<Packet<? super ClientGamePacketListener>> gamePackets
|
||||
) {
|
||||
// The server will not send a ClientboundUpdateDriverInputPacket to the player that initially set the driver input
|
||||
// so Flashback needs to save that data itself. For stuff like players holding space on Pokemon mounts
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
if (player == null) return;
|
||||
// Gather driver Input
|
||||
float vertInput = player.jumping ? 1.0f : (player.isShiftKeyDown() ? -1.0f : 0.0f);
|
||||
Vector3f driverInput = new Vector3f(Math.signum(player.xxa), vertInput, Math.signum(player.zza));
|
||||
gamePackets.add(new ClientboundCustomPayloadPacket(new ClientboundUpdateDriverInputPacket(driverInput, player.getId())));
|
||||
}
|
||||
}
|
||||
-106
@@ -1,106 +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.fabric.mixin.compat;
|
||||
|
||||
import com.cobblemon.mod.common.api.mark.Mark;
|
||||
import com.cobblemon.mod.common.api.mark.Marks;
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls;
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnExtraDataEntityPacket;
|
||||
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokemonPacket;
|
||||
import com.cobblemon.mod.common.pokeball.PokeBall;
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon;
|
||||
import com.cobblemon.mod.common.pokemon.Species;
|
||||
import com.moulberry.flashback.playback.ReplayGamePacketHandler;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
@Mixin(ReplayGamePacketHandler.class)
|
||||
public abstract class ReplayGamePacketHandlerMixin {
|
||||
@Shadow
|
||||
public abstract void handleAddEntity(ClientboundAddEntityPacket clientboundAddEntityPacket);
|
||||
|
||||
@Shadow
|
||||
public abstract ServerLevel level();
|
||||
|
||||
@Shadow(remap = false)
|
||||
private Int2ObjectMap<Entity> pendingEntities;
|
||||
|
||||
@Inject(method = "handleCustomPayload", at = @At("HEAD"))
|
||||
public void cobblemon$handleSpawnEntityWithExtraData(ClientboundCustomPayloadPacket packet, CallbackInfo ci) {
|
||||
if (packet.payload() instanceof SpawnExtraDataEntityPacket<?, ?> cobblemonPacket) {
|
||||
ClientboundAddEntityPacket addEntityPacket = cobblemonPacket.getVanillaSpawnPacket();
|
||||
this.handleAddEntity(addEntityPacket);
|
||||
|
||||
Entity entity = pendingEntities.get(addEntityPacket.getId());
|
||||
if (entity instanceof PokemonEntity pokemonEntity && cobblemonPacket instanceof SpawnPokemonPacket spawnPokemonPacket) {
|
||||
Pokemon pokemon = pokemonEntity.getPokemon();
|
||||
pokemon.setUuid(spawnPokemonPacket.getPokemonUUID());
|
||||
Species species = Optional.ofNullable(PokemonSpecies.INSTANCE.getByIdentifier(spawnPokemonPacket.getSpeciesId()))
|
||||
.orElse(PokemonSpecies.INSTANCE.random());
|
||||
pokemon.setSpecies(species);
|
||||
pokemon.setScaleModifier(spawnPokemonPacket.getScaleModifier());
|
||||
pokemon.setGender(spawnPokemonPacket.getGender());
|
||||
pokemon.setShiny(spawnPokemonPacket.getShiny());
|
||||
pokemon.setForm(pokemon.getSpecies().getFormByShowdownId(spawnPokemonPacket.getFormName()));
|
||||
pokemon.setForcedAspects(spawnPokemonPacket.getAspects());
|
||||
pokemon.setNickname(spawnPokemonPacket.getNickname());
|
||||
ResourceLocation markId = spawnPokemonPacket.getMark();
|
||||
if (markId != null) {
|
||||
pokemon.setActiveMark(Marks.INSTANCE.getByIdentifier(spawnPokemonPacket.getMark()));
|
||||
}
|
||||
PokeBall caughtBall = PokeBalls.INSTANCE.getPokeBall(spawnPokemonPacket.getCaughtBall());
|
||||
if (caughtBall != null) {
|
||||
pokemon.setCaughtBall(caughtBall);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "handleSetEntityPassengersPacket", at = @At("HEAD"), cancellable = true)
|
||||
public void cobblemon$handleSetEntityPassengersPacket(ClientboundSetPassengersPacket packet, CallbackInfo ci) {
|
||||
Entity entity = this.level().getEntity(packet.getVehicle());
|
||||
if (entity instanceof PokemonEntity pokemon) {
|
||||
var passengers = new ArrayList<Entity>();
|
||||
for (int passenger : packet.getPassengers()) {
|
||||
passengers.add(this.level().getEntity(passenger));
|
||||
}
|
||||
Arrays
|
||||
.stream(pokemon.getOccupiedSeats())
|
||||
.filter(x -> !passengers.contains(x))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(Entity::stopRiding);
|
||||
|
||||
var occupiedSeats = Arrays.asList(pokemon.getOccupiedSeats());
|
||||
passengers.stream()
|
||||
.filter(x -> !occupiedSeats.contains(x))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(x -> x.startRiding(pokemon, true));
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,9 +9,7 @@
|
||||
"GameRendererMixin",
|
||||
"GuiMixin",
|
||||
"RecipeBookCategoriesMixin",
|
||||
"pokeball.ModelLoaderMixin",
|
||||
"compat.ReplayGamePacketHandlerMixin",
|
||||
"compat.RecorderMixin"
|
||||
"pokeball.ModelLoaderMixin"
|
||||
],
|
||||
"mixins": [
|
||||
"EntityMixin",
|
||||
|
||||
@@ -100,7 +100,7 @@ kotlin = [ "kotlin-stdlib", "kotlin-reflect" ]
|
||||
fabric = [ "fabric-kotlin", "fabric-permissions" ]
|
||||
common-integrations-compileOnly = [ "adorn-fabric", "jei-api" ]
|
||||
fabric-integrations-implementation = [ "mod-menu" ]
|
||||
fabric-integrations-runtimeOnly = [ "jei-fabric" ]
|
||||
fabric-integrations-runtimeOnly = [ "jei-fabric", "c2me-fabric" ]
|
||||
neoforge-integrations-runtimeOnly = [ "jei-neoforge", "c2me-neoforge" ]
|
||||
mongo = [ "mongo-driver-core", "mongo-driver-sync" ]
|
||||
unitTesting = [ "junit-fabric", "junit-params", "mockito-core", "mock-kotlin", "classgraph" ]
|
||||
|
||||
Reference in New Issue
Block a user