Skip to content

Commit

Permalink
added bird ai to hang around birdhouse if active (#9)
Browse files Browse the repository at this point in the history
* added bird ai to hang around birdhouse if active

* fixed styling errors

* fixed small bug. Removed extraneous functions

* rebased from main, restructured goal logic to fit new ticking structure

* Styling changes, removed dead code in hangoutaroundbirdhousegoal class. Refactored goal class. Added comments

* added bird ai to hang around birdhouse if active

* fixed styling errors

* fixed small bug. Removed extraneous functions
  • Loading branch information
chris7neves authored Mar 14, 2022
1 parent ba69a83 commit 34913ab
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.ocelotslovebirds.birdhaus.blocks;

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

import com.ocelotslovebirds.birdhaus.mobai.HangAroundBirdhouseGoal;
import com.ocelotslovebirds.birdhaus.setup.Registration;
import com.ocelotslovebirds.birdhaus.ticker.FixedIntervalTicker;
import com.ocelotslovebirds.birdhaus.ticker.Ticker;
Expand All @@ -11,12 +13,15 @@
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.ai.goal.WrappedGoal;
import net.minecraft.world.entity.animal.Parrot;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.phys.AABB;
import net.minecraftforge.common.Tags;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
Expand All @@ -35,10 +40,18 @@ public class BirdhouseBlockEntity extends BlockEntity {

private Ticker tickerForBirdSpawns = new FixedIntervalTicker(150);
private Ticker tickerForSeedConsumption = new FixedIntervalTicker(100);
private Ticker tickerForBirdhouseGoalModification = new FixedIntervalTicker(100);

// The block is active if it able to consume seeds
private Boolean isActive = false;

private AABB birdHouseBB = new AABB(
this.getBlockPos().getX() - 10,
this.getBlockPos().getY(),
this.getBlockPos().getZ() - 10,
this.getBlockPos().getX() + 10,
this.getBlockPos().getY() + 10,
this.getBlockPos().getZ() + 10
);
/**
* @param pos Position of the block.
* @param state State of the block being created.
Expand Down Expand Up @@ -69,18 +82,16 @@ public void load(CompoundTag tag) {
super.load(tag);
}


/**
* This is the main loop for the birdhouse. It needs to be improved to allow for the spawning of birds however at
* the moment it works well for
* 1. Extracting seeds from the inventory stack,
* 2. Reacting to seeds being placed in the stack.
* 3. Creates a ticker that can be used to time bird spawns eventually.
* This is the main loop for the birdhouse.
* It ticks all the events that should be happening
* after a certain interval.
*/

public void tickServer() {
handleSeedsForTick();
handleBirdSpawnForTick();
handleParrotGoalForTick();
}

/*
Expand Down Expand Up @@ -110,29 +121,84 @@ private void handleBirdSpawnForTick() {
// Random z offset
int zOffset = ThreadLocalRandom.current().nextInt(-20, 20);
spawnNewBird(xOffset, yOffset, zOffset);

}
}

private void handleParrotGoalForTick() {
if (tickerForBirdhouseGoalModification.tick()) {
if (this.isActive) {
applyBirdHouseGoalToSurroundingParrots();
} else {
removeBirdHouseGoalToSurroundingParrots();
}
}
}

/**
* Applies the "HangingAroundBirdhouseGoal" to birds in the
* birdhouse bounding box.
*
* TODO: Make this threadsafe.
*/
private void applyBirdHouseGoalToSurroundingParrots() {
List<Parrot> parrots = this.level.getEntitiesOfClass(Parrot.class, this.birdHouseBB);
for (Parrot temp:parrots) {
// Check to see if they already have the goal applied. If not, apply it.
if (!temp.goalSelector.getAvailableGoals().stream()
.anyMatch(wg -> wg.getGoal() instanceof HangAroundBirdhouseGoal)) {
temp.goalSelector.addGoal(0, new HangAroundBirdhouseGoal(temp, 1.0, 60, false, this.getBlockPos()));
}
}
}

/**
* Removes the "HangingAroundBirdhouseGoal" to birds in the
* birdhouse bounding box.
*
* TODO: Make this threadsafe.
*/
private void removeBirdHouseGoalToSurroundingParrots() {
List<Parrot> parrots = this.level.getEntitiesOfClass(Parrot.class, this.birdHouseBB);
for (Parrot temp:parrots) {
// Check to see if they already have the goal applied. If not, apply it.
if (temp.goalSelector.getAvailableGoals().stream()
.anyMatch(wg -> wg.getGoal() instanceof HangAroundBirdhouseGoal)) {
Goal toRemove = null;
for (WrappedGoal g : temp.goalSelector.getAvailableGoals()) {
if (g.getGoal() instanceof HangAroundBirdhouseGoal) {
toRemove = g.getGoal();
}
}
if (toRemove != null) {
temp.goalSelector.removeGoal(toRemove);
}
}
}
}

private void handleSeedsForTick() {
if (isActive) {
// If the birdhouse is active, try consuming a seed
// Tick the birdhouse to check it needs to consume a seed
if (tickerForSeedConsumption.tick()) {
// If a seed was successfully extracted from the birdhouse
if (!itemHandler.extractItem(0, 1, false).isEmpty()) {
// If a seed was successfully consumed, set birdhouse to inactive
isActive = false;
}
} else {
// If birdhouse is inactive, start ticking to eventually reactivate it
if (tickerForSeedConsumption.tick()) {
isActive = true;
// Check if the state of the BHouse is not active
if (!this.isActive) {
// If not active, set to active
this.isActive = true;
}
} else { // If nothing was extracted from the BHouse (inventory was empty)
// Set BHouse state to false
this.isActive = false;
}
}

// Update the block state if there was a change
BlockState blockState = getBlockState();
if (blockState.getValue(BlockStateProperties.CONDITIONAL) != isActive) {
if (blockState.getValue(BlockStateProperties.CONDITIONAL) != this.isActive) {
level.setBlock(
worldPosition,
blockState.setValue(BlockStateProperties.CONDITIONAL, isActive),
blockState.setValue(BlockStateProperties.CONDITIONAL, this.isActive),
Block.UPDATE_ALL
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.ocelotslovebirds.birdhaus.mobai;

import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.PathfinderMob;
import net.minecraft.world.entity.ai.goal.RandomStrollGoal;
import net.minecraft.world.phys.Vec3;


public class HangAroundBirdhouseGoal extends RandomStrollGoal {

private Vec3 bHousePosVec;

/**
* Constructor for the parrot goal. Makes parrots stay
* around a birdhouse when it has seeds in its internal inventory.
* @param pMob the mob getting this goal
* @param pSpeedModifier modifies mob move speed
* @param pInterval interval to check if the goal should be sought
* @param pCheckNoActionTime boolean to check to see if the mob has not been performing an action
* @param bHousePos position of the birdhouse passing the goal to the mob
*/
public HangAroundBirdhouseGoal(PathfinderMob pMob, double pSpeedModifier,
int pInterval, boolean pCheckNoActionTime, BlockPos bHousePos) {
super(pMob, pSpeedModifier, pInterval, pCheckNoActionTime);
this.bHousePosVec = new Vec3(bHousePos.getX(), bHousePos.getY(), bHousePos.getZ());
}

/**
* Returns the position for the parrot to move to. This will be the position of the birdhouse that gave it the goal.
* If for some reason, the bird is left with this goal with no birdhouse in sight, it will default to behaving like
* "RandomWanderGoal".
*/
@Override
protected Vec3 getPosition() {
if (this.bHousePosVec != null) {
return this.bHousePosVec;
} else {
return super.getPosition();
}
}
}

0 comments on commit 34913ab

Please sign in to comment.