Skip to content

Commit

Permalink
Firefly swarm test
Browse files Browse the repository at this point in the history
  • Loading branch information
AViewFromTheTop committed Dec 29, 2024
1 parent 738c0ac commit 371ab59
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 14 deletions.
14 changes: 7 additions & 7 deletions src/main/java/net/frozenblock/wilderwild/entity/Firefly.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
package net.frozenblock.wilderwild.entity;

import com.mojang.serialization.Dynamic;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import net.frozenblock.lib.wind.api.WindManager;
Expand All @@ -31,6 +30,7 @@
import net.frozenblock.wilderwild.item.MobBottleItem;
import net.frozenblock.wilderwild.registry.WWDataComponents;
import net.frozenblock.wilderwild.registry.WWItems;
import net.frozenblock.wilderwild.registry.WWMemoryModuleTypes;
import net.frozenblock.wilderwild.registry.WWSounds;
import net.frozenblock.wilderwild.registry.WilderWildRegistries;
import net.frozenblock.wilderwild.tag.WWBiomeTags;
Expand Down Expand Up @@ -63,11 +63,8 @@
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.control.FlyingMoveControl;
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
import net.minecraft.world.entity.ai.navigation.FlyingPathNavigation;
import net.minecraft.world.entity.ai.navigation.PathNavigation;
import net.minecraft.world.entity.ai.sensing.Sensor;
import net.minecraft.world.entity.ai.sensing.SensorType;
import net.minecraft.world.entity.animal.FlyingAnimal;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
Expand All @@ -87,8 +84,6 @@
public class Firefly extends PathfinderMob implements FlyingAnimal, Bottleable {
public static final int RANDOM_FLICKER_AGE_MAX = 19;
public static final int SPAWN_CHANCE = 75;
protected static final List<SensorType<? extends Sensor<? super Firefly>>> SENSORS = List.of(SensorType.NEAREST_LIVING_ENTITIES);
protected static final List<MemoryModuleType<?>> MEMORY_MODULES = List.of(MemoryModuleType.PATH, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryModuleType.WALK_TARGET, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.LOOK_TARGET, MemoryModuleType.HOME);
private static final EntityDataAccessor<Boolean> FROM_BOTTLE = SynchedEntityData.defineId(Firefly.class, EntityDataSerializers.BOOLEAN);
private static final EntityDataAccessor<Integer> AGE = SynchedEntityData.defineId(Firefly.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Float> ANIM_SCALE = SynchedEntityData.defineId(Firefly.class, EntityDataSerializers.FLOAT);
Expand Down Expand Up @@ -161,6 +156,7 @@ public SpawnGroupData finalizeSpawn(
Holder<FireflyColor> fireflyColorHolder = FireflyColors.getSpawnVariant(this.registryAccess(), holder, level.getRandom());
spawnData = new FireflySpawnGroupData(fireflyColorHolder);
this.setColor(fireflyColorHolder.value());
FireflyAi.initAsSwarmLeader(this);
}

return super.finalizeSpawn(level, difficulty, spawnType, spawnData);
Expand Down Expand Up @@ -222,7 +218,7 @@ public boolean canBeLeashed() {
@Override
@NotNull
protected Brain.Provider<Firefly> brainProvider() {
return Brain.provider(MEMORY_MODULES, SENSORS);
return FireflyAi.brainProvider();
}

@Override
Expand Down Expand Up @@ -354,6 +350,10 @@ public boolean shouldHide() {
&& this.level().getBrightness(LightLayer.SKY, this.blockPosition()) >= 6;
}

public boolean isSwarmLeader() {
return this.getBrain().getMemory(WWMemoryModuleTypes.IS_SWARM_LEADER).orElse(false);
}

@Override
@NotNull
protected PathNavigation createNavigation(@NotNull Level level) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
import java.util.List;
import java.util.Optional;
import net.frozenblock.wilderwild.entity.Firefly;
import net.frozenblock.wilderwild.entity.FlowerCow;
import net.frozenblock.wilderwild.registry.WWMemoryModuleTypes;
import net.frozenblock.wilderwild.registry.WWSensorTypes;
import net.minecraft.core.BlockPos;
import net.minecraft.core.GlobalPos;
import net.minecraft.world.entity.LivingEntity;
Expand All @@ -35,20 +38,46 @@
import net.minecraft.world.entity.ai.behavior.PositionTracker;
import net.minecraft.world.entity.ai.behavior.RandomStroll;
import net.minecraft.world.entity.ai.behavior.RunOne;
import net.minecraft.world.entity.ai.behavior.SetEntityLookTarget;
import net.minecraft.world.entity.ai.behavior.SetWalkTargetFromLookTarget;
import net.minecraft.world.entity.ai.behavior.StayCloseToTarget;
import net.minecraft.world.entity.ai.behavior.Swim;
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.schedule.Activity;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class FireflyAi {
protected static final List<SensorType<? extends Sensor<? super Firefly>>> SENSOR_TYPES = List.of(
SensorType.NEAREST_LIVING_ENTITIES,
WWSensorTypes.FIREFLY_LEADER_SENSOR
);
protected static final List<MemoryModuleType<?>> MEMORY_TYPES = List.of(
MemoryModuleType.PATH,
MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES,
MemoryModuleType.WALK_TARGET,
MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE,
MemoryModuleType.LOOK_TARGET,
MemoryModuleType.HOME,
WWMemoryModuleTypes.IS_SWARM_LEADER,
WWMemoryModuleTypes.SWARM_LEADER_TRACKER
);

private FireflyAi() {
}

public static void initAsSwarmLeader(@NotNull Firefly firefly) {
firefly.getBrain().setMemory(WWMemoryModuleTypes.IS_SWARM_LEADER, true);
}

@NotNull
public static Brain.Provider<Firefly> brainProvider() {
return Brain.provider(MEMORY_TYPES, SENSOR_TYPES);
}

@NotNull
public static Brain<?> makeBrain(@NotNull Firefly firefly, @NotNull Brain<Firefly> brain) {
addCoreActivities(brain);
Expand All @@ -75,12 +104,24 @@ private static void addIdleActivities(@NotNull Firefly firefly, @NotNull Brain<F
brain.addActivity(
Activity.IDLE,
ImmutableList.of(
Pair.of(1, new FireflyHide(firefly, 2.0D, 10, 8)),
Pair.of(2, StayCloseToTarget.create(FireflyAi::getLookTarget, entity -> true, 7, 16, 1F)),
Pair.of(4, new RunOne<>(
Pair.of(1, new FireflyHide(firefly, 2D, 10, 8)),
Pair.of(2, StayCloseToTarget.create(FireflyAi::getHomeTarget, entity -> true, 7, 16, 1F)),

// These two are responsible for keeping naturally-spawned Fireflies in swarms
Pair.of(3, StayCloseToTarget.create(FireflyAi::getSwarmLeaderTarget, entity -> true, 5, 8, 1F)),
Pair.of(4, SetEntityLookTarget.create(
livingEntity -> livingEntity.isAlive()
&& !livingEntity.isSpectator()
&& livingEntity instanceof FlowerCow flowerCow
&& flowerCow.hasFlowersLeft()
&& !flowerCow.isBaby(),
8F
)),

Pair.of(5, new RunOne<>(
ImmutableList.of(
Pair.of(RandomStroll.fly(1.0F), 2),
Pair.of(SetWalkTargetFromLookTarget.create(1.0F, 3), 2),
Pair.of(RandomStroll.fly(1F), 2),
Pair.of(SetWalkTargetFromLookTarget.create(1F, 3), 2),
Pair.of(new DoNothing(30, 60), 1)
)
))
Expand Down Expand Up @@ -115,7 +156,12 @@ private static boolean shouldGoTowardsHome(@NotNull LivingEntity firefly, @NotNu
}

@NotNull
private static Optional<PositionTracker> getLookTarget(@NotNull LivingEntity firefly) {
private static Optional<PositionTracker> getSwarmLeaderTarget(@NotNull LivingEntity butterfly) {
return butterfly.getBrain().getMemory(WWMemoryModuleTypes.SWARM_LEADER_TRACKER);
}

@NotNull
private static Optional<PositionTracker> getHomeTarget(@NotNull LivingEntity firefly) {
Brain<?> brain = firefly.getBrain();
Optional<GlobalPos> home = brain.getMemory(MemoryModuleType.HOME);
if (home.isPresent()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 2023-2024 FrozenBlock
* This file is part of Wilder Wild.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>.
*/

package net.frozenblock.wilderwild.entity.ai.firefly;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import net.frozenblock.wilderwild.entity.Firefly;
import net.frozenblock.wilderwild.registry.WWMemoryModuleTypes;
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.behavior.EntityTracker;
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
import net.minecraft.world.entity.ai.sensing.Sensor;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.Set;

public class FireflyLeaderSensor extends Sensor<LivingEntity> {
private static final double FIREFLY_SWARM_LEADER_RANGE = 6D;

@Override
@NotNull
public Set<MemoryModuleType<?>> requires() {
return ImmutableSet.of(MemoryModuleType.NEAREST_LIVING_ENTITIES, WWMemoryModuleTypes.IS_SWARM_LEADER, WWMemoryModuleTypes.SWARM_LEADER_TRACKER);
}

@Override
protected void doTick(@NotNull ServerLevel level, @NotNull LivingEntity entity) {
Brain<?> brain = entity.getBrain();
if (!brain.hasMemoryValue(WWMemoryModuleTypes.IS_SWARM_LEADER) || !brain.getMemory(WWMemoryModuleTypes.IS_SWARM_LEADER).orElse(false)) {
List<LivingEntity> entities = new ArrayList<>(brain.getMemory(MemoryModuleType.NEAREST_LIVING_ENTITIES).orElse(ImmutableList.of()))
.stream()
.filter(livingEntity -> livingEntity.isAlive() && !livingEntity.isSpectator() && entity.distanceTo(livingEntity) <= FIREFLY_SWARM_LEADER_RANGE)
.filter(livingEntity -> livingEntity instanceof Firefly firefly && firefly.isSwarmLeader())
.sorted(Comparator.comparingDouble(entity::distanceToSqr))
.toList();

Optional<LivingEntity> swarmLeader = Optional.ofNullable(entities.getFirst());
if (swarmLeader.isPresent()) {
brain.setMemory(WWMemoryModuleTypes.SWARM_LEADER_TRACKER, new EntityTracker(swarmLeader.get(), true));
return;
}
}
brain.eraseMemory(WWMemoryModuleTypes.SWARM_LEADER_TRACKER);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ protected AABB getTargetSearchArea(double d) {
}

protected void findTarget() {
this.target = this.targetType == Player.class || this.targetType == ServerPlayer.class ? this.mob.level().getNearestPlayer(this.targetConditions, this.mob, this.mob.getX(), this.mob.getEyeY(), this.mob.getZ()) : this.mob.level().getNearestEntity(this.mob.level().getEntitiesOfClass(this.targetType, this.getTargetSearchArea(this.getFollowDistance()), livingEntity -> true), this.targetConditions, this.mob, this.mob.getX(), this.mob.getEyeY(), this.mob.getZ());
this.target = this.targetType == Player.class|| this.targetType == ServerPlayer.class ? this.mob.level().getNearestPlayer(this.targetConditions, this.mob, this.mob.getX(), this.mob.getEyeY(), this.mob.getZ()) : this.mob.level().getNearestEntity(this.mob.level().getEntitiesOfClass(this.targetType, this.getTargetSearchArea(this.getFollowDistance()), livingEntity -> true), this.targetConditions, this.mob, this.mob.getX(), this.mob.getEyeY(), this.mob.getZ());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.util.Unit;
import net.minecraft.world.entity.ai.behavior.PositionTracker;
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
import org.jetbrains.annotations.NotNull;

Expand All @@ -39,6 +40,8 @@ public static void register() {
WWConstants.logWithModId("Registering MemoryModuleTypes for", WWConstants.UNSTABLE_LOGGING);
}

public static final MemoryModuleType<Boolean> IS_SWARM_LEADER = register("is_swarm_leader", Codec.BOOL);
public static final MemoryModuleType<PositionTracker> SWARM_LEADER_TRACKER = register("swarm_leader_tracker");
public static final MemoryModuleType<Boolean> IS_UNDERGROUND = register("is_underground", Codec.BOOL);
public static final MemoryModuleType<List<Crab>> NEARBY_CRABS = register("nearby_crabs");
public static final MemoryModuleType<Integer> HEAL_COOLDOWN_TICKS = register("heal_cooldown_ticks", Codec.INT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import net.frozenblock.wilderwild.entity.ai.crab.CrabCanDigSensor;
import net.frozenblock.wilderwild.entity.ai.crab.CrabNearbyPlayerSensor;
import net.frozenblock.wilderwild.entity.ai.crab.CrabSpecificSensor;
import net.frozenblock.wilderwild.entity.ai.firefly.FireflyLeaderSensor;
import net.frozenblock.wilderwild.entity.ai.ostrich.OstrichAi;
import net.frozenblock.wilderwild.entity.ai.ostrich.OstrichSpecificSensor;
import net.minecraft.core.Registry;
Expand All @@ -43,6 +44,7 @@ public static void register() {
WWConstants.logWithModId("Registering SensorTypes for", WWConstants.UNSTABLE_LOGGING);
}

public static final SensorType<FireflyLeaderSensor> FIREFLY_LEADER_SENSOR = register("firefly_leader_sensor", FireflyLeaderSensor::new);
public static final SensorType<CrabSpecificSensor> CRAB_SPECIFIC_SENSOR = register("crab_specific_sensor", CrabSpecificSensor::new);
public static final SensorType<TemptingSensor> CRAB_TEMPTATIONS = register("crab_temptations", () -> new TemptingSensor(CrabAi.getTemptations()));
public static final SensorType<CrabNearbyPlayerSensor> CRAB_NEARBY_PLAYER_SENSOR = register("crab_nearby_player_sensor", CrabNearbyPlayerSensor::new);
Expand Down

0 comments on commit 371ab59

Please sign in to comment.