From e23aa6b0667664ce79cb83ca3f0b91db2017fb7c Mon Sep 17 00:00:00 2001 From: Guilherme Pereira Date: Sat, 22 Nov 2025 19:39:21 -0300 Subject: [PATCH 1/4] add partner mark molang callback --- .../mod/common/api/molang/MoLangFunctions.kt | 31 ++++++++++++++- .../player_tick_pre/partner_mark.molang | 39 +++++++++++++++++++ .../data/cobblemon/marks/mark_partner.json | 3 +- .../item/recipe_filters/colour_seasoning.json | 3 +- 4 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 common/src/main/resources/data/cobblemon/callbacks/player_tick_pre/partner_mark.molang diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/api/molang/MoLangFunctions.kt b/common/src/main/kotlin/com/cobblemon/mod/common/api/molang/MoLangFunctions.kt index a98c8c055c..b61556b143 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/api/molang/MoLangFunctions.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/api/molang/MoLangFunctions.kt @@ -779,6 +779,20 @@ object MoLangFunctions { battleStartResult.ifSuccessful { returnValue = it.struct } return@put returnValue } + map.put("get_custom_stat") { params -> + val statName = params.getString(0) + + val resourceLocation = ResourceLocation.tryParse(statName) ?: return@put DoubleValue.ZERO + val statResourceLocation = BuiltInRegistries.CUSTOM_STAT.get(resourceLocation) ?: return@put DoubleValue.ZERO + + val exists = net.minecraft.stats.Stats.CUSTOM.contains(statResourceLocation) + if (!exists) return@put DoubleValue.ZERO + + val stat = net.minecraft.stats.Stats.CUSTOM.get(statResourceLocation) + val value = player.stats.getValue(stat) + + DoubleValue(value) + } } map } @@ -1739,22 +1753,35 @@ object MoLangFunctions { pokemon.removeCosmeticItem() } map.put("add_marks") { params -> + var appliedMark = false for (param in params.params) { val identifier = param.asString().asIdentifierDefaultingNamespace() val mark = Marks.getByIdentifier(identifier) - if (mark != null) pokemon.exchangeMark(mark, true) + if (mark != null) { + pokemon.exchangeMark(mark, true) + appliedMark = true + } } + + DoubleValue(appliedMark) } map.put("add_marks_with_chance") { params -> + var appliedMark = false for (param in params.params) { val identifier = param.asString().asIdentifierDefaultingNamespace() val mark = Marks.getByIdentifier(identifier) + mark?.let { val probability = it.chance.coerceIn(0F, 1F) * 100 val randomValue = Random.nextDouble(0.0, 100.0) - if (randomValue < probability) pokemon.exchangeMark(it, true) + if (randomValue < probability) { + pokemon.exchangeMark(it, true) + appliedMark = true + } } } + + DoubleValue(appliedMark) } map.put("add_potential_marks") { params -> for (param in params.params) { diff --git a/common/src/main/resources/data/cobblemon/callbacks/player_tick_pre/partner_mark.molang b/common/src/main/resources/data/cobblemon/callbacks/player_tick_pre/partner_mark.molang new file mode 100644 index 0000000000..f98cfede57 --- /dev/null +++ b/common/src/main/resources/data/cobblemon/callbacks/player_tick_pre/partner_mark.molang @@ -0,0 +1,39 @@ +t.ticks_between_checks = 20 * 10; +math.mod(q.player.world.game_time, t.ticks_between_checks) != 0 ? { + return 0; +}; + +t.steps_required = 10000; +t.friendship_required = 200; + +t.total_blocks = + q.player.get_custom_stat('walk_one_cm') + + q.player.get_custom_stat('crouch_one_cm') + + q.player.get_custom_stat('sprint_one_cm') + + q.player.get_custom_stat('walk_on_water_one_cm') + + q.player.get_custom_stat('fall_one_cm') + + q.player.get_custom_stat('climb_one_cm') + + q.player.get_custom_stat('fly_one_cm') + + q.player.get_custom_stat('walk_under_water_one_cm') + + q.player.get_custom_stat('minecart_one_cm') + + q.player.get_custom_stat('boat_one_cm') + + q.player.get_custom_stat('pig_one_cm') + + q.player.get_custom_stat('horse_one_cm') + + q.player.get_custom_stat('aviate_one_cm') + + q.player.get_custom_stat('swim_one_cm') + + q.player.get_custom_stat('strider_one_cm'); + +t.total_blocks = t.total_blocks / 100.0; +t.player_data = q.player.data(); + +math.floor(t.total_blocks / t.steps_required) > math.floor(t.player_data.last_partner_mark_check / t.steps_required) ? { + t.party = q.player.party; + for_each(t.pokemon, t.party.pokemon, { + t.pokemon.friendship >= t.friendship_required ? { + t.pokemon.add_marks_with_chance('cobblemon:mark_partner'); + }; + }); +}; + +q.print(t.total_blocks); +t.player_data.last_partner_mark_check = t.total_blocks; \ No newline at end of file diff --git a/common/src/main/resources/data/cobblemon/marks/mark_partner.json b/common/src/main/resources/data/cobblemon/marks/mark_partner.json index ae40918753..2ed3bcc438 100644 --- a/common/src/main/resources/data/cobblemon/marks/mark_partner.json +++ b/common/src/main/resources/data/cobblemon/marks/mark_partner.json @@ -4,5 +4,6 @@ "titleColor": "40B282", "description": "cobblemon.mark.mark_partner.desc", "texture": "cobblemon:textures/gui/mark/mark_partner.png", - "indexNumber": 104 + "indexNumber": 104, + "chance": 0.01 } \ No newline at end of file diff --git a/common/src/main/resources/data/cobblemon/tags/item/recipe_filters/colour_seasoning.json b/common/src/main/resources/data/cobblemon/tags/item/recipe_filters/colour_seasoning.json index 3ae3809276..881b76ce84 100644 --- a/common/src/main/resources/data/cobblemon/tags/item/recipe_filters/colour_seasoning.json +++ b/common/src/main/resources/data/cobblemon/tags/item/recipe_filters/colour_seasoning.json @@ -4,7 +4,6 @@ "#cobblemon:recipe_filters/bait_seasoning", "#cobblemon:recipe_filters/effect_seasoning", "#cobblemon:recipe_filters/flavour_seasoning", - "#cobblemon:recipe_filters/nutrition_seasoning", - "#cobblemon:recipe_filters/poke_puff_seasoner" + "#cobblemon:recipe_filters/nutrition_seasoning" ] } \ No newline at end of file From 4723f915006da76b8b69093821f3779d34741349 Mon Sep 17 00:00:00 2001 From: Guilherme Pereira Date: Sat, 22 Nov 2025 21:57:25 -0300 Subject: [PATCH 2/4] add riding stats --- .../mod/common/mixin/ServerPlayerMixin.java | 38 +++++++++++ .../mod/common/api/stats/CobblemonStats.kt | 63 +++++++++++++------ .../mod/common/events/StatHandler.kt | 26 ++------ .../assets/cobblemon/lang/en_us.json | 5 +- .../player_tick_pre/partner_mark.molang | 34 +++++----- .../cobblemon/mod/fabric/CobblemonFabric.kt | 7 ++- .../mod/neoforge/CobblemonNeoForge.kt | 28 +++------ 7 files changed, 121 insertions(+), 80 deletions(-) diff --git a/common/src/main/java/com/cobblemon/mod/common/mixin/ServerPlayerMixin.java b/common/src/main/java/com/cobblemon/mod/common/mixin/ServerPlayerMixin.java index ad585d5841..069589b397 100644 --- a/common/src/main/java/com/cobblemon/mod/common/mixin/ServerPlayerMixin.java +++ b/common/src/main/java/com/cobblemon/mod/common/mixin/ServerPlayerMixin.java @@ -11,8 +11,10 @@ package com.cobblemon.mod.common.mixin; import com.cobblemon.mod.common.Cobblemon; import com.cobblemon.mod.common.OrientationControllable; import com.cobblemon.mod.common.PlayerSpawnerAccessor; +import com.cobblemon.mod.common.api.riding.RidingStyle; import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner; import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory; +import com.cobblemon.mod.common.api.stats.CobblemonStats; import com.cobblemon.mod.common.entity.pokemon.PokemonEntity; import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; @@ -89,4 +91,40 @@ public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor { private boolean cobblemon$cancelSavingPokemonMounts(boolean original, @Local(ordinal=0) Entity entity) { return original && !(entity instanceof PokemonEntity); } + + @Inject(method = "checkRidingStatistics", at = @At("TAIL")) + public void cobblemon$checkRidingStatistics(double dx, double dy, double dz, CallbackInfo ci) { + var player = (ServerPlayer)(Object)this; + if (!player.isPassenger() || cobblemon$didNotMove(dx, dy, dz)) return; + + var vehicle = player.getVehicle(); + if (!(vehicle instanceof PokemonEntity pokemonEntity)) return; + + var ridingController = pokemonEntity.getRidingController(); + if (ridingController == null) return; + + var activeContext = ridingController.getContext(); + if (activeContext == null) return; + + var ridingStyle = activeContext.getStyle(); + if (ridingStyle == null) return; + + int distance = Math.round((float) Math.sqrt(dx * dx + dy * dy + dz * dz) * 100.0F); + switch (ridingStyle) { + case RidingStyle.LAND: + player.awardStat(CobblemonStats.INSTANCE.getStat(CobblemonStats.INSTANCE.getRIDING_LAND()), distance); + break; + case RidingStyle.AIR: + player.awardStat(CobblemonStats.INSTANCE.getStat(CobblemonStats.INSTANCE.getRIDING_AIR()), distance); + break; + case RidingStyle.LIQUID: + player.awardStat(CobblemonStats.INSTANCE.getStat(CobblemonStats.INSTANCE.getRIDING_LIQUID()), distance); + break; + } + } + + @Unique + private static boolean cobblemon$didNotMove(double dx, double dy, double dz) { + return dx == 0.0 && dy == 0.0 && dz == 0.0; + } } diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/api/stats/CobblemonStats.kt b/common/src/main/kotlin/com/cobblemon/mod/common/api/stats/CobblemonStats.kt index 966949845d..8764ede8fc 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/api/stats/CobblemonStats.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/api/stats/CobblemonStats.kt @@ -8,30 +8,37 @@ package com.cobblemon.mod.common.api.stats +import com.cobblemon.mod.common.Cobblemon +import net.minecraft.core.registries.BuiltInRegistries import net.minecraft.resources.ResourceLocation +import net.minecraft.stats.StatFormatter object CobblemonStats { - val stats = mutableMapOf() + val stats = mutableMapOf() - var CAPTURED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "captured") //makeCustomStat("captured", StatFormatter.DEFAULT) - val SHINIES_CAPTURED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "shinies_captured") //makeCustomStat("shinies_captured", StatFormatter.DEFAULT) - val RELEASED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "released") //makeCustomStat("released", StatFormatter.DEFAULT) - val EVOLVED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "evolved") //makeCustomStat("evolved", StatFormatter.DEFAULT) - val LEVEL_UP: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "level_up") //makeCustomStat("level_up", StatFormatter.DEFAULT) - val BATTLES_WON: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "battles_won") //makeCustomStat("battles_won", StatFormatter.DEFAULT) - val BATTLES_LOST: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "battles_lost") //makeCustomStat("battles_lost", StatFormatter.DEFAULT) - val BATTLES_FLED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "battles_fled") //makeCustomStat("battles_fled", StatFormatter.DEFAULT) - val BATTLES_TOTAL: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "battles_total") //makeCustomStat("battles_total", StatFormatter.DEFAULT) - val DEX_ENTRIES: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "dex_entries") //makeCustomStat("dex_entries", StatFormatter.DEFAULT) - val EGGS_COLLECTED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "eggs_collected") //makeCustomStat("eggs_collected", StatFormatter.DEFAULT) - val EGGS_HATCHED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "eggs_hatched") //makeCustomStat("eggs_hatched", StatFormatter.DEFAULT) - val TRADED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "traded") //makeCustomStat("traded", StatFormatter.DEFAULT) - val FOSSILS_REVIVED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "fossils_revived") //makeCustomStat("fossils_revived", StatFormatter.DEFAULT) - val TIMES_RIDDEN: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "times_ridden") - val ROD_CASTS: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "rod_casts") - val REEL_INS: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "reel_ins") - val POKEMON_INTERACTED_WITH: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "pokemon_interacted_with") //makeCustomStat("pokemon_interacted_with", StatFormatter.DEFAULT) - //TODO block, stats (interact, gimmi), riding (styles?) + var CAPTURED: CobblemonStat = CobblemonStat("captured") + val SHINIES_CAPTURED: CobblemonStat = CobblemonStat("shinies_captured") + val RELEASED: CobblemonStat = CobblemonStat("released") + val EVOLVED: CobblemonStat = CobblemonStat("evolved") + val LEVEL_UP: CobblemonStat = CobblemonStat("level_up") + val BATTLES_WON: CobblemonStat = CobblemonStat("battles_won") + val BATTLES_LOST: CobblemonStat = CobblemonStat("battles_lost") + val BATTLES_FLED: CobblemonStat = CobblemonStat("battles_fled") + val BATTLES_TOTAL: CobblemonStat = CobblemonStat("battles_total") + val DEX_ENTRIES: CobblemonStat = CobblemonStat("dex_entries") + val EGGS_COLLECTED: CobblemonStat = CobblemonStat("eggs_collected") + val EGGS_HATCHED: CobblemonStat = CobblemonStat("eggs_hatched") + val TRADED: CobblemonStat = CobblemonStat("traded") + val FOSSILS_REVIVED: CobblemonStat = CobblemonStat("fossils_revived") + val TIMES_RIDDEN: CobblemonStat = CobblemonStat("times_ridden") + val ROD_CASTS: CobblemonStat = CobblemonStat("rod_casts") + val REEL_INS: CobblemonStat = CobblemonStat("reel_ins") + val POKEMON_INTERACTED_WITH: CobblemonStat = CobblemonStat("pokemon_interacted_with") + val RIDING_LAND: CobblemonStat = CobblemonStat("riding_land", StatFormatter.DISTANCE) + val RIDING_AIR: CobblemonStat = CobblemonStat("riding_air", StatFormatter.DISTANCE) + val RIDING_LIQUID: CobblemonStat = CobblemonStat("riding_liquid", StatFormatter.DISTANCE) + + //TODO block, stats (interact, gimmi) fun registerStats() { stats["captured"] = CAPTURED @@ -52,5 +59,21 @@ object CobblemonStats { stats["rod_casts"] = ROD_CASTS stats["reel_ins"] = REEL_INS stats["pokemon_interacted_with"] = POKEMON_INTERACTED_WITH + stats["riding_land"] = RIDING_LAND + stats["riding_air"] = RIDING_AIR + stats["riding_liquid"] = RIDING_LIQUID + } + + fun getStat(cobblemonStat: CobblemonStat) : ResourceLocation { + val resourceLocation = cobblemonStat.resourceLocation + val stat = BuiltInRegistries.CUSTOM_STAT.get(resourceLocation) + if (stat == null) { + Cobblemon.LOGGER.error("Could not find stat with id {}", resourceLocation) + } + return stat ?: throw NullPointerException("Could not find stat with id $resourceLocation") + } + + data class CobblemonStat(val path: String, val formatter: StatFormatter = StatFormatter.DEFAULT) { + val resourceLocation: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", path); } } diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/events/StatHandler.kt b/common/src/main/kotlin/com/cobblemon/mod/common/events/StatHandler.kt index 3ca5595730..d0c8d15200 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/events/StatHandler.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/events/StatHandler.kt @@ -30,21 +30,13 @@ import com.cobblemon.mod.common.api.events.battles.BattleStartedEvent import com.cobblemon.mod.common.api.events.battles.BattleVictoryEvent import com.cobblemon.mod.common.api.events.fishing.PokerodCastEvent import com.cobblemon.mod.common.api.events.fishing.PokerodReelEvent -import com.cobblemon.mod.common.api.events.pokemon.CollectEggEvent -import com.cobblemon.mod.common.api.events.pokemon.FossilRevivedEvent -import com.cobblemon.mod.common.api.events.pokemon.HatchEggEvent -import com.cobblemon.mod.common.api.events.pokemon.LevelUpEvent -import com.cobblemon.mod.common.api.events.pokemon.PokemonCapturedEvent -import com.cobblemon.mod.common.api.events.pokemon.PokemonGainedEvent -import com.cobblemon.mod.common.api.events.pokemon.RidePokemonEvent -import com.cobblemon.mod.common.api.events.pokemon.TradeEvent +import com.cobblemon.mod.common.api.events.pokemon.* import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionCompleteEvent import com.cobblemon.mod.common.api.events.storage.ReleasePokemonEvent +import com.cobblemon.mod.common.api.stats.CobblemonStats.getStat import com.cobblemon.mod.common.util.getPlayer -import net.minecraft.core.registries.BuiltInRegistries -import net.minecraft.resources.ResourceLocation import net.minecraft.server.level.ServerPlayer -import java.util.UUID +import java.util.* object StatHandler : EventHandler { override fun registerListeners() { @@ -100,13 +92,13 @@ object StatHandler : EventHandler { fun onBattleStart(event : BattleStartedEvent) { event.battle.players.forEach { player -> - player.awardStat(this.getStat(getStat(Cobblemon.statistics.BATTLES_TOTAL))) + player.awardStat(getStat(Cobblemon.statistics.BATTLES_TOTAL)) } } fun onDexEntryGain(event : PokemonGainedEvent) { val player = event.pokemon.getOwnerPlayer() - player?.awardStat(getStat(getStat(Cobblemon.statistics.DEX_ENTRIES))) + player?.awardStat(getStat(Cobblemon.statistics.DEX_ENTRIES)) } fun onCollectEgg(event : CollectEggEvent) { @@ -139,12 +131,4 @@ object StatHandler : EventHandler { fun onReelIn(event : PokerodReelEvent) { event.player.awardStat(getStat(Cobblemon.statistics.REEL_INS)) } - - fun getStat(resourceLocation: ResourceLocation) : ResourceLocation { - val stat = BuiltInRegistries.CUSTOM_STAT.get(resourceLocation) - if (stat == null) { - Cobblemon.LOGGER.error("Could not find stat with id {}", resourceLocation) - } - return stat ?: throw NullPointerException("Could not find stat with id $resourceLocation") - } } diff --git a/common/src/main/resources/assets/cobblemon/lang/en_us.json b/common/src/main/resources/assets/cobblemon/lang/en_us.json index ed2794889c..6a26ebb9f3 100644 --- a/common/src/main/resources/assets/cobblemon/lang/en_us.json +++ b/common/src/main/resources/assets/cobblemon/lang/en_us.json @@ -9440,5 +9440,8 @@ "stat.cobblemon.traded": "Pokémon Traded", "stat.cobblemon.times_ridden": "Pokémon Ridden", "stat.cobblemon.rod_casts": "PokéRod Casts", - "stat.cobblemon.reel_ins": "PokéRod Catches" + "stat.cobblemon.reel_ins": "PokéRod Catches", + "stat.cobblemon.riding_land": "Distance by Pokémon on Land", + "stat.cobblemon.riding_air": "Distance by Pokémon in Air", + "stat.cobblemon.riding_liquid": "Distance by Pokémon in Liquid" } diff --git a/common/src/main/resources/data/cobblemon/callbacks/player_tick_pre/partner_mark.molang b/common/src/main/resources/data/cobblemon/callbacks/player_tick_pre/partner_mark.molang index f98cfede57..1e446fc6df 100644 --- a/common/src/main/resources/data/cobblemon/callbacks/player_tick_pre/partner_mark.molang +++ b/common/src/main/resources/data/cobblemon/callbacks/player_tick_pre/partner_mark.molang @@ -7,21 +7,24 @@ t.steps_required = 10000; t.friendship_required = 200; t.total_blocks = - q.player.get_custom_stat('walk_one_cm') + - q.player.get_custom_stat('crouch_one_cm') + - q.player.get_custom_stat('sprint_one_cm') + - q.player.get_custom_stat('walk_on_water_one_cm') + - q.player.get_custom_stat('fall_one_cm') + - q.player.get_custom_stat('climb_one_cm') + - q.player.get_custom_stat('fly_one_cm') + - q.player.get_custom_stat('walk_under_water_one_cm') + - q.player.get_custom_stat('minecart_one_cm') + - q.player.get_custom_stat('boat_one_cm') + - q.player.get_custom_stat('pig_one_cm') + - q.player.get_custom_stat('horse_one_cm') + - q.player.get_custom_stat('aviate_one_cm') + - q.player.get_custom_stat('swim_one_cm') + - q.player.get_custom_stat('strider_one_cm'); + q.player.get_custom_stat('minecraft:walk_one_cm') + + q.player.get_custom_stat('minecraft:crouch_one_cm') + + q.player.get_custom_stat('minecraft:sprint_one_cm') + + q.player.get_custom_stat('minecraft:walk_on_water_one_cm') + + q.player.get_custom_stat('minecraft:fall_one_cm') + + q.player.get_custom_stat('minecraft:climb_one_cm') + + q.player.get_custom_stat('minecraft:fly_one_cm') + + q.player.get_custom_stat('minecraft:walk_under_water_one_cm') + + q.player.get_custom_stat('minecraft:minecart_one_cm') + + q.player.get_custom_stat('minecraft:boat_one_cm') + + q.player.get_custom_stat('minecraft:pig_one_cm') + + q.player.get_custom_stat('minecraft:horse_one_cm') + + q.player.get_custom_stat('minecraft:aviate_one_cm') + + q.player.get_custom_stat('minecraft:swim_one_cm') + + q.player.get_custom_stat('minecraft:strider_one_cm') + + q.player.get_custom_stat('cobblemon:riding_land') + + q.player.get_custom_stat('cobblemon:riding_air') + + q.player.get_custom_stat('cobblemon:riding_liquid'); t.total_blocks = t.total_blocks / 100.0; t.player_data = q.player.data(); @@ -35,5 +38,4 @@ math.floor(t.total_blocks / t.steps_required) > math.floor(t.player_data.last_pa }); }; -q.print(t.total_blocks); t.player_data.last_partner_mark_check = t.total_blocks; \ No newline at end of file diff --git a/fabric/src/main/kotlin/com/cobblemon/mod/fabric/CobblemonFabric.kt b/fabric/src/main/kotlin/com/cobblemon/mod/fabric/CobblemonFabric.kt index 1ff8e7c71e..b178c4f0b7 100644 --- a/fabric/src/main/kotlin/com/cobblemon/mod/fabric/CobblemonFabric.kt +++ b/fabric/src/main/kotlin/com/cobblemon/mod/fabric/CobblemonFabric.kt @@ -68,6 +68,7 @@ import net.minecraft.server.level.ServerPlayer import net.minecraft.server.packs.PackType import net.minecraft.server.packs.resources.PreparableReloadListener import net.minecraft.server.packs.resources.ResourceManager +import net.minecraft.stats.Stats import net.minecraft.tags.TagKey import net.minecraft.util.profiling.ProfilerFiller import net.minecraft.world.InteractionResult @@ -92,8 +93,10 @@ object CobblemonFabric : CobblemonImplementation { Cobblemon.preInitialize(this) Cobblemon.statistics.registerStats() - Cobblemon.statistics.stats.forEach { - Registry.register(BuiltInRegistries.CUSTOM_STAT, it.value, it.value) + Cobblemon.statistics.stats.forEach { entry -> + val cobblemonStat = entry.value + Registry.register(BuiltInRegistries.CUSTOM_STAT, cobblemonStat.resourceLocation, cobblemonStat.resourceLocation) + Stats.CUSTOM.get(cobblemonStat.resourceLocation, cobblemonStat.formatter) } Cobblemon.initialize() diff --git a/neoforge/src/main/kotlin/com/cobblemon/mod/neoforge/CobblemonNeoForge.kt b/neoforge/src/main/kotlin/com/cobblemon/mod/neoforge/CobblemonNeoForge.kt index 8ed132f8cb..59d4b3d7e7 100644 --- a/neoforge/src/main/kotlin/com/cobblemon/mod/neoforge/CobblemonNeoForge.kt +++ b/neoforge/src/main/kotlin/com/cobblemon/mod/neoforge/CobblemonNeoForge.kt @@ -11,14 +11,7 @@ package com.cobblemon.mod.neoforge import com.cobblemon.mod.common.* import com.cobblemon.mod.common.advancement.CobblemonCriteria import com.cobblemon.mod.common.advancement.predicate.CobblemonEntitySubPredicates -import com.cobblemon.mod.common.api.net.serializers.IdentifierDataSerializer -import com.cobblemon.mod.common.api.net.serializers.NPCPlayerTextureSerializer -import com.cobblemon.mod.common.api.net.serializers.PlatformTypeDataSerializer -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.net.serializers.UUIDSetDataSerializer -import com.cobblemon.mod.common.api.net.serializers.Vec3DataSerializer +import com.cobblemon.mod.common.api.net.serializers.* import com.cobblemon.mod.common.item.group.CobblemonItemGroups import com.cobblemon.mod.common.loot.LootInjector import com.cobblemon.mod.common.particle.CobblemonParticles @@ -37,13 +30,9 @@ import com.cobblemon.mod.neoforge.net.CobblemonNeoForgeNetworkManager import com.cobblemon.mod.neoforge.permission.ForgePermissionValidator import com.cobblemon.mod.neoforge.worldgen.CobblemonBiomeModifiers import com.mojang.brigadier.arguments.ArgumentType -import java.util.Optional -import java.util.UUID import net.minecraft.commands.synchronization.ArgumentTypeInfo import net.minecraft.commands.synchronization.ArgumentTypeInfos -import net.minecraft.core.registries.BuiltInRegistries 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.MinecraftServer @@ -58,6 +47,7 @@ import net.minecraft.server.packs.repository.Pack import net.minecraft.server.packs.repository.Pack.Position import net.minecraft.server.packs.repository.PackSource import net.minecraft.server.packs.resources.PreparableReloadListener +import net.minecraft.stats.Stats import net.minecraft.tags.TagKey import net.minecraft.world.item.CreativeModeTab import net.minecraft.world.item.CreativeModeTab.TabVisibility @@ -77,12 +67,7 @@ import net.neoforged.fml.loading.FMLEnvironment import net.neoforged.neoforge.common.ItemAbilities import net.neoforged.neoforge.common.NeoForge import net.neoforged.neoforge.common.NeoForgeMod -import net.neoforged.neoforge.event.AddPackFindersEvent -import net.neoforged.neoforge.event.AddReloadListenerEvent -import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent -import net.neoforged.neoforge.event.LootTableLoadEvent -import net.neoforged.neoforge.event.OnDatapackSyncEvent -import net.neoforged.neoforge.event.RegisterCommandsEvent +import net.neoforged.neoforge.event.* import net.neoforged.neoforge.event.entity.EntityAttributeCreationEvent import net.neoforged.neoforge.event.entity.player.PlayerEvent import net.neoforged.neoforge.event.entity.player.PlayerWakeUpEvent @@ -95,6 +80,7 @@ import net.neoforged.neoforge.registries.NeoForgeRegistries import net.neoforged.neoforge.registries.RegisterEvent import net.neoforged.neoforge.server.ServerLifecycleHooks import thedarkcolour.kotlinforforge.neoforge.forge.MOD_BUS +import java.util.* import kotlin.reflect.KClass @Mod(Cobblemon.MODID) @@ -221,8 +207,10 @@ class CobblemonNeoForge : CobblemonImplementation { event.register(Registries.CUSTOM_STAT) { registry -> Cobblemon.statistics.registerStats() - Cobblemon.statistics.stats.forEach { (key, value) -> - registry.register(value, ResourceLocation.fromNamespaceAndPath("cobblemon", key)) + Cobblemon.statistics.stats.forEach { entry -> + val cobblemonStat = entry.value + registry.register(cobblemonStat.resourceLocation, cobblemonStat.resourceLocation) + Stats.CUSTOM.get(cobblemonStat.resourceLocation, cobblemonStat.formatter) } } } From 7cedfb90471387cf0197ecf98b43bb3f98387e14 Mon Sep 17 00:00:00 2001 From: Guilherme Pereira Date: Sat, 22 Nov 2025 22:02:14 -0300 Subject: [PATCH 3/4] update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33559d16e7..c3d7cdb580 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## [1.7.1 (MONTH xth, 2025)](#1-7-1) ### Additions +- Added riding statistics: `Distance by Pokémon on Land`, `Distance by Pokémon in Air` and `Distance by Pokémon in Liquid`. +- Added the Partner Mark, which party Pokémon have a very small chance to earn as the player walks, provided they have enough friendship. ### Changes - Convert the riding freelook button to a configurable keybinding From 690ccbd26091078bc9b71d7f9017c62bf50913ad Mon Sep 17 00:00:00 2001 From: Guilherme Pereira Date: Mon, 8 Dec 2025 12:06:20 -0300 Subject: [PATCH 4/4] refactor check riding statistics method for server player mixin --- .../mod/common/mixin/ServerPlayerMixin.java | 44 ++++++++----------- .../mod/common/api/stats/CobblemonStats.kt | 22 ++++++++++ 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/common/src/main/java/com/cobblemon/mod/common/mixin/ServerPlayerMixin.java b/common/src/main/java/com/cobblemon/mod/common/mixin/ServerPlayerMixin.java index 069589b397..e5e572d3f3 100644 --- a/common/src/main/java/com/cobblemon/mod/common/mixin/ServerPlayerMixin.java +++ b/common/src/main/java/com/cobblemon/mod/common/mixin/ServerPlayerMixin.java @@ -18,6 +18,8 @@ import com.cobblemon.mod.common.api.stats.CobblemonStats; import com.cobblemon.mod.common.entity.pokemon.PokemonEntity; import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Local; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; @@ -92,39 +94,31 @@ public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor { return original && !(entity instanceof PokemonEntity); } - @Inject(method = "checkRidingStatistics", at = @At("TAIL")) - public void cobblemon$checkRidingStatistics(double dx, double dy, double dz, CallbackInfo ci) { - var player = (ServerPlayer)(Object)this; - if (!player.isPassenger() || cobblemon$didNotMove(dx, dy, dz)) return; - - var vehicle = player.getVehicle(); - if (!(vehicle instanceof PokemonEntity pokemonEntity)) return; + @WrapOperation(method = "checkRidingStatistics", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;getVehicle()Lnet/minecraft/world/entity/Entity;")) + public Entity cobblemon$checkRidingStatistics(ServerPlayer player, Operation original, @Local int distance) { + var entity = original.call(player); + if (!(entity instanceof PokemonEntity pokemonEntity)) { + return entity; + } var ridingController = pokemonEntity.getRidingController(); - if (ridingController == null) return; + if (ridingController == null) return entity; var activeContext = ridingController.getContext(); - if (activeContext == null) return; + if (activeContext == null) return entity; var ridingStyle = activeContext.getStyle(); - if (ridingStyle == null) return; + CobblemonStats.CobblemonStat stat = switch (ridingStyle) { + case RidingStyle.LAND -> CobblemonStats.RIDING_LAND; + case RidingStyle.AIR -> CobblemonStats.RIDING_AIR; + case RidingStyle.LIQUID -> CobblemonStats.RIDING_LIQUID; + default -> null; + }; - int distance = Math.round((float) Math.sqrt(dx * dx + dy * dy + dz * dz) * 100.0F); - switch (ridingStyle) { - case RidingStyle.LAND: - player.awardStat(CobblemonStats.INSTANCE.getStat(CobblemonStats.INSTANCE.getRIDING_LAND()), distance); - break; - case RidingStyle.AIR: - player.awardStat(CobblemonStats.INSTANCE.getStat(CobblemonStats.INSTANCE.getRIDING_AIR()), distance); - break; - case RidingStyle.LIQUID: - player.awardStat(CobblemonStats.INSTANCE.getStat(CobblemonStats.INSTANCE.getRIDING_LIQUID()), distance); - break; + if (stat != null) { + player.awardStat(CobblemonStats.getStat(stat), distance); } - } - @Unique - private static boolean cobblemon$didNotMove(double dx, double dy, double dz) { - return dx == 0.0 && dy == 0.0 && dz == 0.0; + return entity; } } diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/api/stats/CobblemonStats.kt b/common/src/main/kotlin/com/cobblemon/mod/common/api/stats/CobblemonStats.kt index 8764ede8fc..2e4abd2516 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/api/stats/CobblemonStats.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/api/stats/CobblemonStats.kt @@ -16,26 +16,47 @@ import net.minecraft.stats.StatFormatter object CobblemonStats { val stats = mutableMapOf() + @JvmField var CAPTURED: CobblemonStat = CobblemonStat("captured") + @JvmField val SHINIES_CAPTURED: CobblemonStat = CobblemonStat("shinies_captured") + @JvmField val RELEASED: CobblemonStat = CobblemonStat("released") + @JvmField val EVOLVED: CobblemonStat = CobblemonStat("evolved") + @JvmField val LEVEL_UP: CobblemonStat = CobblemonStat("level_up") + @JvmField val BATTLES_WON: CobblemonStat = CobblemonStat("battles_won") + @JvmField val BATTLES_LOST: CobblemonStat = CobblemonStat("battles_lost") + @JvmField val BATTLES_FLED: CobblemonStat = CobblemonStat("battles_fled") + @JvmField val BATTLES_TOTAL: CobblemonStat = CobblemonStat("battles_total") + @JvmField val DEX_ENTRIES: CobblemonStat = CobblemonStat("dex_entries") + @JvmField val EGGS_COLLECTED: CobblemonStat = CobblemonStat("eggs_collected") + @JvmField val EGGS_HATCHED: CobblemonStat = CobblemonStat("eggs_hatched") + @JvmField val TRADED: CobblemonStat = CobblemonStat("traded") + @JvmField val FOSSILS_REVIVED: CobblemonStat = CobblemonStat("fossils_revived") + @JvmField val TIMES_RIDDEN: CobblemonStat = CobblemonStat("times_ridden") + @JvmField val ROD_CASTS: CobblemonStat = CobblemonStat("rod_casts") + @JvmField val REEL_INS: CobblemonStat = CobblemonStat("reel_ins") + @JvmField val POKEMON_INTERACTED_WITH: CobblemonStat = CobblemonStat("pokemon_interacted_with") + @JvmField val RIDING_LAND: CobblemonStat = CobblemonStat("riding_land", StatFormatter.DISTANCE) + @JvmField val RIDING_AIR: CobblemonStat = CobblemonStat("riding_air", StatFormatter.DISTANCE) + @JvmField val RIDING_LIQUID: CobblemonStat = CobblemonStat("riding_liquid", StatFormatter.DISTANCE) //TODO block, stats (interact, gimmi) @@ -64,6 +85,7 @@ object CobblemonStats { stats["riding_liquid"] = RIDING_LIQUID } + @JvmStatic fun getStat(cobblemonStat: CobblemonStat) : ResourceLocation { val resourceLocation = cobblemonStat.resourceLocation val stat = BuiltInRegistries.CUSTOM_STAT.get(resourceLocation)