mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-20 22:26:24 -04:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ff62821cd | ||
|
|
1fb300cd86 | ||
|
|
dae01c545d |
@@ -9,13 +9,21 @@
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonItems;
|
||||
import net.minecraft.world.entity.monster.piglin.PiglinAi;
|
||||
import com.cobblemon.mod.common.CobblemonMemories;
|
||||
import com.cobblemon.mod.common.entity.ai.PiglinDanceTarget;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import net.minecraft.world.entity.ai.Brain;
|
||||
import net.minecraft.world.entity.monster.piglin.*;
|
||||
import net.minecraft.world.entity.schedule.Activity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
||||
@Mixin(PiglinAi.class)
|
||||
public class PiglinBarterMixin {
|
||||
@@ -29,5 +37,31 @@ public class PiglinBarterMixin {
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "makeBrain", at = @At("TAIL"), cancellable = true)
|
||||
private static void cobblemon$makeBrain(Piglin piglin, Brain<Piglin> brain, CallbackInfoReturnable<Brain<?>> cir) {
|
||||
// Get access to private task map
|
||||
brain.addActivityAndRemoveMemoryWhenStopped(Activity.INVESTIGATE, 10,
|
||||
ImmutableList.of(
|
||||
new PiglinDanceTarget()
|
||||
), CobblemonMemories.INSTANCE.getNEAREST_LOVED_ENTITY());
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
method = "updateActivity(Lnet/minecraft/world/entity/monster/piglin/Piglin;)V",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/entity/ai/Brain;setActiveActivityToFirstValid(Ljava/util/List;)V"
|
||||
)
|
||||
)
|
||||
private static void redirectSetActiveActivityToFirstValid(
|
||||
Brain<Piglin> brain,
|
||||
List<Activity> originalList
|
||||
) {
|
||||
// Add new activity to the front
|
||||
List<Activity> newList = new ArrayList<>(List.of(Activity.INVESTIGATE));
|
||||
newList.addAll(originalList);
|
||||
|
||||
// Call original method with modified list
|
||||
brain.setActiveActivityToFirstValid(newList);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,19 @@
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonItems;
|
||||
import com.cobblemon.mod.common.CobblemonMemories;
|
||||
import com.cobblemon.mod.common.CobblemonSensors;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
|
||||
import net.minecraft.world.entity.ai.sensing.Sensor;
|
||||
import net.minecraft.world.entity.ai.sensing.SensorType;
|
||||
import net.minecraft.world.entity.monster.piglin.Piglin;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
@@ -28,4 +37,27 @@ public abstract class PiglinEntityMixin {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
@Mutable
|
||||
private static ImmutableList<SensorType<? extends Sensor<? super Piglin>>> SENSOR_TYPES;
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
@Mutable
|
||||
private static ImmutableList<MemoryModuleType<?>> MEMORY_TYPES;
|
||||
|
||||
@Inject(method = "<clinit>", at = @At("TAIL"))
|
||||
private static void cobblemon$onInit(CallbackInfo ci) {
|
||||
SENSOR_TYPES = ImmutableList.<SensorType<? extends Sensor<? super Piglin>>>builder()
|
||||
.addAll(SENSOR_TYPES)
|
||||
.add(CobblemonSensors.INSTANCE.getNEARBY_PIGLIN_LOVED_POKEMON())
|
||||
.build();
|
||||
MEMORY_TYPES = ImmutableList.<MemoryModuleType<?>>builder()
|
||||
.addAll(MEMORY_TYPES)
|
||||
.add(CobblemonMemories.INSTANCE.getNEAREST_LOVED_ENTITY())
|
||||
.build();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.ai.Brain;
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
|
||||
import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities;
|
||||
import net.minecraft.world.entity.ai.sensing.PiglinSpecificSensor;
|
||||
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.Optional;
|
||||
|
||||
@Mixin(PiglinSpecificSensor.class)
|
||||
public abstract class PiglinSpecificSensorMixin {
|
||||
|
||||
@Inject(method = "doTick", at = @At("TAIL"))
|
||||
protected void cobblemon$doTick(ServerLevel level, LivingEntity entity, CallbackInfo ci) {
|
||||
Brain<?> brain = entity.getBrain();
|
||||
if (!brain.hasMemoryValue(MemoryModuleType.NEAREST_VISIBLE_ZOMBIFIED)) {
|
||||
NearestVisibleLivingEntities nearestVisibleLivingEntities = brain.getMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES).orElse(NearestVisibleLivingEntities.empty());
|
||||
Optional<LivingEntity> fearedEntity = Optional.empty();
|
||||
for (LivingEntity livingEntity : nearestVisibleLivingEntities.findAll((x) -> true)) {
|
||||
if (fearedEntity.isEmpty() && livingEntity instanceof PokemonEntity && ((PokemonEntity) livingEntity).getPokemon().getSpecies().getBehaviour().getEntityInteract().getAvoidedByPiglin()) {
|
||||
fearedEntity = Optional.of(livingEntity);
|
||||
brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_ZOMBIFIED, livingEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common
|
||||
import com.cobblemon.mod.common.api.ai.CobblemonAttackTargetData
|
||||
import com.cobblemon.mod.common.api.dialogue.ActiveDialogue
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.ListCodec
|
||||
import com.mojang.serialization.codecs.PrimitiveCodec
|
||||
@@ -48,6 +49,7 @@ object CobblemonMemories {
|
||||
/** how many are following me rn? */
|
||||
val HERD_SIZE = register<Int>("herd_size") // Don't bother saving it, we'll try to keep count roughly.
|
||||
val ATTACK_TARGET_DATA = register<CobblemonAttackTargetData>("attack_target_data") // This is used to store additional information about the attack target, such as when to give up pursuit.
|
||||
val NEAREST_LOVED_ENTITY = register<PokemonEntity>("nearst_loved_entity")
|
||||
|
||||
fun <U> register(id: String, codec: Codec<U>): MemoryModuleType<U> {
|
||||
val memoryModule = MemoryModuleType(Optional.of(codec))
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.entity.pokemon.ai.sensors.DefendOwnerSensor
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.DrowsySensor
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.PokemonAdultSensor
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.PokemonGrowableCropSensor
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.PokemonPiglinLovedSensor
|
||||
import com.cobblemon.mod.common.pokemon.ai.PokemonDisturbancesSensor
|
||||
import com.cobblemon.mod.common.entity.sensor.BattlingPokemonSensor
|
||||
import com.cobblemon.mod.common.entity.sensor.NPCBattlingSensor
|
||||
@@ -36,6 +37,8 @@ object CobblemonSensors {
|
||||
|
||||
val NEARBY_GROWABLE_CROPS = register("nearby_growable_crops", ::PokemonGrowableCropSensor)
|
||||
|
||||
val NEARBY_PIGLIN_LOVED_POKEMON = register("nearby_golden_pokemon", ::PokemonPiglinLovedSensor)
|
||||
|
||||
fun <E : Entity, U : Sensor<E>> register(id: String, supplier: Supplier<U>): SensorType<U> {
|
||||
val sensor = SensorType(supplier)
|
||||
sensors[id] = sensor
|
||||
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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.ai
|
||||
|
||||
/*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.ai.behavior.Behavior
|
||||
import net.minecraft.world.entity.ai.behavior.EntityTracker
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.entity.ai.util.LandRandomPos
|
||||
import net.minecraft.world.entity.monster.piglin.Piglin
|
||||
import java.util.*
|
||||
|
||||
class PiglinDanceTarget : Behavior<Piglin>(
|
||||
ImmutableMap.of(
|
||||
CobblemonMemories.NEAREST_LOVED_ENTITY, MemoryStatus.VALUE_PRESENT,
|
||||
MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED,
|
||||
),
|
||||
Int.MAX_VALUE,
|
||||
Int.MAX_VALUE
|
||||
) {
|
||||
var lovedPokemon: PokemonEntity? = null
|
||||
val wayTooFar = 20F
|
||||
var tooFar = 5F
|
||||
var closeEnough = 3F
|
||||
var tooClose = 1.5F
|
||||
|
||||
override fun checkExtraStartConditions(level: ServerLevel, owner: Piglin): Boolean {
|
||||
lovedPokemon = (owner.brain.getMemory(CobblemonMemories.NEAREST_LOVED_ENTITY).orElse(null) ?: return false)
|
||||
return lovedPokemon != null
|
||||
}
|
||||
|
||||
override fun canStillUse(level: ServerLevel, entity: Piglin, gameTime: Long) : Boolean {
|
||||
return lovedPokemon != null && lovedPokemon?.isAlive == true && (lovedPokemon?.distanceTo(entity) ?: 999F) < wayTooFar
|
||||
}
|
||||
|
||||
|
||||
override fun tick(level: ServerLevel, entity: Piglin, gameTime: Long) {
|
||||
val leader : PokemonEntity = lovedPokemon ?: return
|
||||
if (entity.brain.hasMemoryValue(MemoryModuleType.WALK_TARGET)) {
|
||||
return // We're busy goin' n' shit
|
||||
}
|
||||
|
||||
if (leader.distanceTo(entity) > tooFar) {
|
||||
entity.brain.setMemory(
|
||||
MemoryModuleType.WALK_TARGET,
|
||||
CobblemonWalkTarget(
|
||||
pos = leader.blockPosition(),
|
||||
speedModifier = 0.6F,
|
||||
completionRange = closeEnough.toInt()
|
||||
)
|
||||
)
|
||||
} else if (leader.distanceTo(entity) < tooClose) {
|
||||
// Give the dude some space
|
||||
for (j in 0..9) {
|
||||
val vec3 = LandRandomPos.getPosAway(entity, 5, 7, leader.position())
|
||||
if (vec3 != null) {
|
||||
entity.brain.setMemory(
|
||||
MemoryModuleType.WALK_TARGET,
|
||||
WalkTarget(
|
||||
vec3,
|
||||
0.4F,
|
||||
closeEnough.toInt()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
} else if (leader.brain.hasMemoryValue(MemoryModuleType.WALK_TARGET)) {
|
||||
// Go to the leader's walk target, roughly.
|
||||
val walkTarget = leader.brain.getMemory(MemoryModuleType.WALK_TARGET).orElse(null) ?: return
|
||||
entity.brain.setMemory(
|
||||
MemoryModuleType.WALK_TARGET,
|
||||
CobblemonWalkTarget(
|
||||
pos = walkTarget.target.currentBlockPosition(),
|
||||
speedModifier = walkTarget.speedModifier,
|
||||
nodeTypeFilter = (walkTarget as? CobblemonWalkTarget)?.nodeTypeFilter ?: { true },
|
||||
completionRange = closeEnough.toInt()
|
||||
)
|
||||
)
|
||||
} else {
|
||||
// Maybe wander around and mingle
|
||||
if (entity.random.nextFloat() < 0.01f) {
|
||||
val vec3 = LandRandomPos.getPosTowards(entity,5, 7, leader.position())
|
||||
if (vec3 != null) {
|
||||
entity.brain.setMemory(
|
||||
MemoryModuleType.WALK_TARGET,
|
||||
WalkTarget(
|
||||
vec3,
|
||||
0.5F,
|
||||
1
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun start(level: ServerLevel, entity: Piglin, gameTime: Long) {
|
||||
val pokemonEntity = lovedPokemon ?: return
|
||||
entity.brain.setMemory(MemoryModuleType.DANCING, true)
|
||||
entity.brain.setMemory(MemoryModuleType.CELEBRATE_LOCATION, Optional.of(pokemonEntity.blockPosition()))
|
||||
entity.brain.setMemory(MemoryModuleType.LOOK_TARGET, EntityTracker(pokemonEntity, true))
|
||||
}
|
||||
|
||||
override fun stop(level: ServerLevel, entity: Piglin, gameTime: Long) {
|
||||
entity.brain.setMemory(MemoryModuleType.DANCING, false)
|
||||
entity.brain.eraseMemory(MemoryModuleType.CELEBRATE_LOCATION)
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.pokemon.ai.sensors
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities
|
||||
import net.minecraft.world.entity.ai.sensing.Sensor
|
||||
|
||||
/**
|
||||
* Senses when the Pokémon is near an adult of the same species.
|
||||
*
|
||||
* @author JazzMcNade
|
||||
* @since May 15th, 2024
|
||||
*/
|
||||
class PokemonPiglinLovedSensor : Sensor<LivingEntity>(100) {
|
||||
override fun requires() = setOf(CobblemonMemories.NEAREST_LOVED_ENTITY, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES)
|
||||
|
||||
override fun doTick(world: ServerLevel, entity: LivingEntity) {
|
||||
entity.brain.getMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES).ifPresent { visibleMobs ->
|
||||
setNearestPokemonAdult(entity, visibleMobs)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setNearestPokemonAdult(entity: LivingEntity, visibleMobs: NearestVisibleLivingEntities) {
|
||||
val nearestGoldenIdol = visibleMobs.findClosest { mob ->
|
||||
mob is PokemonEntity && mob.exposedSpecies.behaviour.entityInteract.lovedByPiglin
|
||||
}.map { mob -> mob as PokemonEntity }
|
||||
|
||||
entity.brain.setMemory(CobblemonMemories.NEAREST_LOVED_ENTITY, nearestGoldenIdol)
|
||||
}
|
||||
}
|
||||
@@ -22,12 +22,16 @@ class EntityBehaviour {
|
||||
val avoidedByCreeper = false
|
||||
val avoidedByPhantom = false
|
||||
val avoidedBySkeleton = false
|
||||
val lovedByPiglin = false
|
||||
val avoidedByPiglin = false
|
||||
|
||||
@Transient
|
||||
val struct = ObjectValue(this).also {
|
||||
it.addFunction("avoided_by_creeper") { DoubleValue(avoidedByCreeper) }
|
||||
it.addFunction("avoided_by_phantom") { DoubleValue(avoidedByPhantom) }
|
||||
it.addFunction("avoided_by_skeleton") { DoubleValue(avoidedBySkeleton) }
|
||||
it.addFunction("loved_by_piglin") { DoubleValue(lovedByPiglin) }
|
||||
it.addFunction("avoid_by_piglin") { DoubleValue(avoidedByPiglin) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -58,6 +58,9 @@
|
||||
"fly": {
|
||||
"canFly": true
|
||||
}
|
||||
},
|
||||
"entityInteract": {
|
||||
"avoidedByPiglin": true
|
||||
}
|
||||
},
|
||||
"drops": {
|
||||
|
||||
@@ -52,6 +52,11 @@
|
||||
"resting": {
|
||||
"canSleep": true,
|
||||
"light": "0-4"
|
||||
},
|
||||
"entityInteract": {
|
||||
"avoidedByCreeper": true,
|
||||
"avoidedByPhantom": true,
|
||||
"lovedByPiglin": true
|
||||
},
|
||||
"moving": {
|
||||
"swim": {
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
"PhantomSweepAttackGoalMixin",
|
||||
"PiglinBarterMixin",
|
||||
"PiglinEntityMixin",
|
||||
"PiglinSpecificSensorMixin",
|
||||
"PlayerAdvancementsMixin",
|
||||
"PlayerMixin",
|
||||
"PointedDripstoneBlockMixin",
|
||||
|
||||
Reference in New Issue
Block a user