Skip to content

Commit

Permalink
Way better boids
Browse files Browse the repository at this point in the history
  • Loading branch information
N1nn1 committed May 8, 2024
1 parent db33ce2 commit ca9b5f3
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 57 deletions.
64 changes: 61 additions & 3 deletions src/main/java/com/ninni/spawn/entity/Herring.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,88 @@
import com.ninni.spawn.entity.common.BoidFishEntity;
import com.ninni.spawn.registry.SpawnItems;
import com.ninni.spawn.registry.SpawnSoundEvents;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.entity.SpawnGroupData;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.control.SmoothSwimmingLookControl;
import net.minecraft.world.entity.ai.control.SmoothSwimmingMoveControl;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.ServerLevelAccessor;
import org.jetbrains.annotations.Nullable;

public class Herring extends BoidFishEntity {
private static final EntityDataAccessor<Integer> SCHOOL_SIZE = SynchedEntityData.defineId(Herring.class, EntityDataSerializers.INT);
public Herring(EntityType<? extends BoidFishEntity> entityType, Level level) {
super(entityType, level);
}

@Override
public @Nullable SpawnGroupData finalizeSpawn(ServerLevelAccessor serverLevelAccessor, DifficultyInstance difficultyInstance, MobSpawnType mobSpawnType, @Nullable SpawnGroupData spawnGroupData, @Nullable CompoundTag compoundTag) {
if (mobSpawnType != MobSpawnType.BUCKET) {
this.setSchoolSize(random.nextInt(15) + 5);
}
return super.finalizeSpawn(serverLevelAccessor, difficultyInstance, mobSpawnType, spawnGroupData, compoundTag);
}

public static AttributeSupplier.Builder createAttributes() {
return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 2.0);
}

@Override
public void tick() {
super.tick();
if (this.getMaxSchoolSize() != this.getSchoolSize()) this.SetMaxSchoolSize(this.getSchoolSize());
}

protected void defineSynchedData() {
super.defineSynchedData();
this.entityData.define(SCHOOL_SIZE, 0);
}

public void addAdditionalSaveData(CompoundTag compoundTag) {
super.addAdditionalSaveData(compoundTag);
compoundTag.putInt("SchoolSize", this.getSchoolSize());
}

public void readAdditionalSaveData(CompoundTag compoundTag) {
super.readAdditionalSaveData(compoundTag);
this.setSchoolSize(compoundTag.getInt("SchoolSize"));
}

public void saveToBucketTag(ItemStack itemStack) {
super.saveToBucketTag(itemStack);
CompoundTag compoundTag = itemStack.getOrCreateTag();
compoundTag.putInt("SchoolSize", this.getSchoolSize());
}

@Override
public void loadFromBucketTag(CompoundTag compoundTag) {
super.loadFromBucketTag(compoundTag);
if (compoundTag.contains("SchoolSize")) this.setSchoolSize(compoundTag.getInt("SchoolSize"));
}

public void setSchoolSize(int i) {
this.entityData.set(SCHOOL_SIZE, i);
}

public int getSchoolSize() {
return this.entityData.get(SCHOOL_SIZE);
}


@Override
public int getMaxSchoolSize() {
return 15;
return this.getSchoolSize();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class BoidFishSchoolingGoal extends Goal {
public final float alignmentInfluence;
public final float cohesionInfluence;
private final BoidFishEntity mob;
private int timer = 0;

public BoidFishSchoolingGoal(BoidFishEntity mob, float separationInfluence, float separationRange, float alignmentInfluence, float cohesionInfluence) {
this.mob = mob;
Expand All @@ -28,33 +29,30 @@ public BoidFishSchoolingGoal(BoidFishEntity mob, float separationInfluence, floa

@Override
public boolean canUse() {
return mob.isInWaterOrBubble() && (mob.isFollower() || mob.hasFollowers());
return mob.isInWaterOrBubble() && (mob.isFollower() || mob.hasFollowers()) && mob.cantFollowTimer == 0;
}

public void tick() {
mob.addDeltaMovement(separation());
if (mob.horizontalCollision) timer++;
if (timer > 60) mob.cantFollowTimer = 60;

mob.addDeltaMovement(random());
mob.addDeltaMovement(separation());
mob.addDeltaMovement(cohesion());
mob.addDeltaMovement(alignment());
}

public Vec3 random() {
var velocity = mob.getDeltaMovement();

if (Mth.abs((float) velocity.x) < 0.1 && Mth.abs((float) velocity.z) < 0.1)
return new Vec3(randomSign() * 0.2, 0, randomSign() * 0.2);
if (Mth.abs((float) velocity.x) < 0.1 && Mth.abs((float) velocity.z) < 0.1 && mob.hasFollowers())
return new Vec3(randomSign() * 0.4, 0, randomSign() * 0.4);

return Vec3.ZERO;
}

public int randomSign() {
var isNegative = mob.getRandom().nextBoolean();

if (isNegative) {
return -1;
}

return 1;
return mob.getRandom().nextBoolean() ? -1 : 1;
}

public Vec3 separation() {
Expand Down
15 changes: 4 additions & 11 deletions src/main/java/com/ninni/spawn/entity/ai/goal/HeightBoundsGoal.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,13 @@ public void tick() {
}

public Vec3 bounds() {
var amount = 0.1;
var yAmount = 0.1;
var dY = Mth.abs((float) mob.getDeltaMovement().y);

if (dY > amount) {
amount = dY;
}
if (dY > yAmount) yAmount = dY;



if (this.isTooHigh()) {
return new Vec3(0, -amount, 0);
}
if (this.isTooLow())
return new Vec3(0, amount, 0);
if (this.isTooHigh()) return new Vec3(0, -yAmount, 0);
if (this.isTooLow()) return new Vec3(0, yAmount, 0);

return Vec3.ZERO;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,11 @@

public class LimitSpeedAndLookInVelocityDirectionGoal extends Goal {
private final BoidFishEntity mob;
private final float minSpeed;
private final float maxSpeed;
private final float speed;

public LimitSpeedAndLookInVelocityDirectionGoal(BoidFishEntity mob, float minSpeed, float maxSpeed) {
public LimitSpeedAndLookInVelocityDirectionGoal(BoidFishEntity mob, float speed) {
this.mob = mob;
this.minSpeed = minSpeed;
this.maxSpeed = maxSpeed;
this.speed = speed;
}

@Override
Expand All @@ -27,14 +25,7 @@ public boolean canUse() {

@Override
public void tick() {
var velocity = mob.getDeltaMovement();
var speed = velocity.length();

if (speed < minSpeed)
velocity = velocity.normalize().scale(minSpeed);
if (speed > maxSpeed)
velocity = velocity.normalize().scale(maxSpeed);

var velocity = mob.getDeltaMovement().normalize().scale(0.2).scale(speed);
mob.setDeltaMovement(velocity);
mob.lookAt(EntityAnchorArgument.Anchor.EYES, mob.position().add(velocity.scale(3)));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,10 @@ protected int nextStartTick(BoidFishEntity abstractSchoolingFish) {

@Override
public boolean canUse() {
if (this.fish.hasFollowers()) {
return false;
}
if (this.fish.isFollower()) {
return true;
}
if (this.fish.hasFollowers()) return false;

if (this.fish.isFollower()) return true;

if (this.nextStartTick > 0) {
--this.nextStartTick;
return false;
Expand Down
30 changes: 18 additions & 12 deletions src/main/java/com/ninni/spawn/entity/common/BoidFishEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public abstract class BoidFishEntity extends AbstractFish {
@Nullable
public BoidFishEntity leader;
public List<BoidFishEntity> ownSchool = new ArrayList<>();
private int maxSchoolSize;
public int cantFollowTimer;

public BoidFishEntity(EntityType<? extends AbstractFish> entityType, Level level) {
super(entityType, level);
Expand All @@ -35,26 +37,26 @@ protected void registerGoals() {
this.goalSelector.addGoal(4, new FishSwimGoal(this));
this.goalSelector.addGoal(5, new BoidFishSchoolingGoal(this, 0.2f, 0.4f, 8 / 20f, 1 / 20f));
this.goalSelector.addGoal(3, new HeightBoundsGoal(this));
this.goalSelector.addGoal(2, new LimitSpeedAndLookInVelocityDirectionGoal(this, 0.3f, 0.4f));
this.goalSelector.addGoal(2, new LimitSpeedAndLookInVelocityDirectionGoal(this, 0.65f));
this.goalSelector.addGoal(5, new OrganizeBoidSchoolingGoal(this));
}

@Override
public int getMaxSpawnClusterSize() {
return this.getMaxSchoolSize();
}

public int getMaxSchoolSize() {
return super.getMaxSpawnClusterSize();
return maxSchoolSize;
}
public void SetMaxSchoolSize(int i) {
this.maxSchoolSize = i;
}

public boolean isFollower() {
return this.leader != null && this.leader.isAlive();
}

public void startFollowing(BoidFishEntity abstractSchoolingFish) {
this.leader = abstractSchoolingFish;
abstractSchoolingFish.addToOwnSchoolFollower(this);
if (this.cantFollowTimer == 0) {
this.leader = abstractSchoolingFish;
abstractSchoolingFish.addToOwnSchoolFollower(this);
}
}

public void stopFollowing() {
Expand All @@ -70,20 +72,24 @@ protected SoundEvent getSwimSound() {
}

private void addToOwnSchoolFollower(BoidFishEntity entity) {
this.ownSchool.add(entity);
if (entity.cantFollowTimer == 0) this.ownSchool.add(entity);
}

private void removeFollowerFromOwnSchool(BoidFishEntity entity) {
this.ownSchool.remove(entity);
}

public boolean canBeFollowed() {
return this.hasFollowers() && this.ownSchool.size() < this.getMaxSchoolSize();
return this.hasFollowers() && this.ownSchool.size() < this.getMaxSchoolSize() && this.cantFollowTimer == 0;
}

@Override
public void tick() {
super.tick();
if (this.cantFollowTimer > 0) {
this.cantFollowTimer--;
this.stopFollowing();
}
}

public boolean hasFollowers() {
Expand All @@ -95,7 +101,7 @@ public void addFollowers(Stream<? extends BoidFishEntity> stream) {
}

public boolean inRangeOfLeader() {
return this.distanceToSqr(this.leader) <= 121.0;
return this.distanceToSqr(this.leader) <= 200.0;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public class SpawnCreativeModeTab {

ItemGroupEvents.modifyEntriesEvent(CreativeModeTabs.SPAWN_EGGS).register(entries -> {
entries.addAfter(Items.ALLAY_SPAWN_EGG, ANGLER_FISH_SPAWN_EGG, ANT_SPAWN_EGG);
entries.addAfter(Items.CHICKEN, CLAM_SPAWN_EGG);
entries.addAfter(Items.CHICKEN_SPAWN_EGG, CLAM_SPAWN_EGG);
entries.addAfter(Items.OCELOT_SPAWN_EGG, OCTOPUS_SPAWN_EGG);
entries.addAfter(Items.SALMON_SPAWN_EGG, SEA_COW_SPAWN_EGG, SEAHORSE_SPAWN_EGG, SEA_LION_SPAWN_EGG);
entries.addAfter(Items.SLIME_SPAWN_EGG, SNAIL_SPAWN_EGG);
Expand Down

0 comments on commit ca9b5f3

Please sign in to comment.