Skip to content

Commit

Permalink
Reworked AI to pathfinding link: (#10543)
Browse files Browse the repository at this point in the history
-AI now passes along more information about safe target locations and is using better fitting pathfinding tasks when going to buildings All pathfinding calls now return true on reaching their target, and false while walking unlike being mixed before All logic for creating pathing tasks is now consolidated in a dedicated util: EntityNavigationUtils, slimming down the Navigator class a bit.
  • Loading branch information
someaddons authored Dec 22, 2024
1 parent 5f82e61 commit 7c1f25e
Show file tree
Hide file tree
Showing 80 changed files with 990 additions and 1,212 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -506,10 +506,4 @@ default boolean canEat(final ItemStack stack)
{
return true;
}

/**
* Get the standing position for a building.
* @return the standing pos.
*/
BlockPos getStandingPosition();
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import com.minecolonies.api.entity.ai.statemachine.tickratestatemachine.TickRateStateMachine;
import com.minecolonies.api.entity.citizen.citizenhandlers.*;
import com.minecolonies.api.entity.other.MinecoloniesMinecart;
import com.minecolonies.api.entity.pathfinding.proxy.IWalkToProxy;
import com.minecolonies.api.entity.pathfinding.registry.IPathNavigateRegistry;
import com.minecolonies.api.inventory.InventoryCitizen;
import com.minecolonies.api.sounds.EventType;
Expand Down Expand Up @@ -554,15 +553,6 @@ public boolean checkCanDropLoot()
*/
public abstract ILocation getLocation();

/**
* Checks if a worker is at his working site. If he isn't, sets it's path to the location
*
* @param site the place where he should walk to
* @param range Range to check in
* @return True if worker is at site, otherwise false.
*/
public abstract boolean isWorkerAtSiteWithMove(@NotNull BlockPos site, int range);

/**
* Getter for the citizendata. Tries to get it from the colony is the data is null.
*
Expand Down Expand Up @@ -593,13 +583,6 @@ public boolean checkCanDropLoot()
*/
public abstract void playMoveAwaySound();

/**
* Get the path proxy of the citizen.
*
* @return the proxy.
*/
public abstract IWalkToProxy getProxy();

/**
* Decrease the saturation of the citizen for 1 action.
*/
Expand Down
27 changes: 0 additions & 27 deletions src/main/java/com/minecolonies/api/util/BlockPosUtil.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.minecolonies.api.util;

import com.ldtteam.structurize.util.BlockUtils;
import com.minecolonies.api.entity.citizen.AbstractEntityCitizen;
import com.minecolonies.api.util.constant.ColonyConstants;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
Expand All @@ -14,7 +13,6 @@
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
Expand Down Expand Up @@ -667,31 +665,6 @@ public static boolean setBlock(@NotNull final Level worldIn, @NotNull final Bloc
return worldIn.setBlock(coords, state, flag);
}

/**
* @param living A living entity.
* @param destination chunk coordinates to check moving to.
* @return True when XYZ is found, an set moving to, otherwise false.
*/
public static boolean tryMoveBaseCitizenEntityToXYZ(@NotNull final AbstractEntityCitizen living, @NotNull final BlockPos destination)
{
if (!(living instanceof LivingEntity))
{
return false;
}

return EntityUtils.tryMoveLivingToXYZ(living, destination.getX(), destination.getY(), destination.getZ());
}

/**
* @param living A living entity.
* @param destination chunk coordinates to check moving to.
* @return True when XYZ is found, an set moving to, otherwise false.
*/
public static boolean tryMoveLivingToXYZ(@NotNull final Mob living, @NotNull final BlockPos destination)
{
return EntityUtils.tryMoveLivingToXYZ(living, destination.getX(), destination.getY(), destination.getZ());
}

/**
* Create a method for using a {@link BlockPos}.
*
Expand Down
58 changes: 9 additions & 49 deletions src/main/java/com/minecolonies/api/util/EntityUtils.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.minecolonies.api.util;

import com.ldtteam.structurize.util.BlockUtils;
import com.minecolonies.api.crafting.ItemStorage;
import com.minecolonies.api.entity.citizen.AbstractEntityCitizen;
import com.minecolonies.api.entity.other.AbstractFastMinecoloniesEntity;
import com.minecolonies.api.items.ModTags;
import com.minecolonies.core.entity.pathfinding.PathfindingUtils;
import com.minecolonies.core.entity.pathfinding.SurfaceType;
import com.minecolonies.core.entity.pathfinding.navigation.EntityNavigationUtils;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.tags.BlockTags;
Expand All @@ -17,7 +17,6 @@
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.minecraftforge.common.util.FakePlayer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand Down Expand Up @@ -216,6 +215,7 @@ private static boolean checkValidSpawn(@NotNull final BlockGetter world, final B
|| SurfaceType.getSurfaceType(world, world.getBlockState(pos.below(2)), pos.below(2)) == SurfaceType.WALKABLE;
}

// TODO: Move out movement stuff

/**
* Sets the movement of the entity to specific point. Returns true if direction is set, otherwise false.
Expand All @@ -239,27 +239,15 @@ public static boolean tryMoveLivingToXYZ(@NotNull final Mob living, final int x,
* @param y y-coordinate
* @param z z-coordinate
* @param speedFactor Speedfactor to modify base speed with
* @return True if the path is set to destination, otherwise false
* @return true if arrived
*/
public static boolean tryMoveLivingToXYZ(@NotNull final Mob living, final int x, final int y, final int z, final double speedFactor)
{
return living.getNavigation().moveTo(x, y, z, speedFactor);
}

/**
* {@link #isLivingAtSiteWithMove(LivingEntity, int, int, int)}
*
* @param entity entity to check
* @param x X-coordinate
* @param y Y-coordinate
* @param z Z-coordinate
* @return True if entity is at site, otherwise false
*/
public static boolean isLivingAtSiteWithMove(@NotNull final LivingEntity entity, final int x, final int y, final int z)
{
//Default range of 3 works better
//Range of 2 get some entitys stuck
return isLivingAtSiteWithMove(entity, x, y, z, DEFAULT_MOVE_RANGE);
if (living instanceof AbstractFastMinecoloniesEntity entity)
{
return EntityNavigationUtils.walkToPos(entity, new BlockPos(x, y, z), 4, true, speedFactor);
}
return true;
}

/**
Expand Down Expand Up @@ -300,34 +288,6 @@ public static boolean isLivingAtSiteWithMove(@NotNull final LivingEntity entity,
return EntityUtils.isLivingAtSite(entity, x, y, z, range);
}

/**
* Checks if a certain entity is in the world at a certain position already.
*
* @param entity the entity.
* @param world the world.
* @param placer the entity to get the itemstacks from to check.
* @return true if there.
*/
public static boolean isEntityAtPosition(final Entity entity, final Level world, final Entity placer)
{
final List<ItemStorage> existingReq = ItemStackUtils.getListOfStackForEntity(entity, placer);
final BlockPos pos = BlockPos.containing(entity.getX(), entity.getY(), entity.getZ());
return world.getEntitiesOfClass(Entity.class, new AABB(pos.offset(1, 1, 1), pos.offset(-1, -1, -1)))
.stream()
.anyMatch(ent -> ent.getX() == entity.getX() && ent.getY() == entity.getY() && ent.getZ() == entity.getZ() && ItemStackUtils.getListOfStackForEntity(entity, placer)
.equals(existingReq));
}

public static boolean isEntityAtPosition(final Entity entity, final Level world, final AbstractEntityCitizen entityCitizen)
{
if (entity != null)
{
return EntityUtils.isEntityAtPosition(entity, world, (Entity) entityCitizen);
}

return false;
}

/**
* Returns whether or not the entity is within a specific range of his working site.
*
Expand Down
77 changes: 0 additions & 77 deletions src/main/java/com/minecolonies/api/util/ItemStackUtils.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.minecolonies.api.util;

import com.google.common.collect.Lists;
import com.minecolonies.api.advancements.AdvancementTriggers;
import com.minecolonies.api.colony.ICitizenData;
import com.minecolonies.api.colony.IColony;
Expand All @@ -27,14 +26,12 @@
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.ItemTags;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.decoration.ArmorStand;
import net.minecraft.world.entity.decoration.ItemFrame;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.item.*;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BrewingStandBlockEntity;
import net.minecraft.world.level.block.entity.FurnaceBlockEntity;
import net.minecraft.world.phys.EntityHitResult;
Expand Down Expand Up @@ -140,80 +137,6 @@ private ItemStackUtils()
*/
}

/**
* Get the entity of an entityInfo object.
*
* @param entityData the input.
* @param world the world.
* @return the output object or null.
*/
@Nullable
public static Entity getEntityFromEntityInfoOrNull(final CompoundTag entityData, final Level world)
{
try
{
final Optional<EntityType<?>> type = EntityType.by(entityData);
if (type.isPresent())
{
final Entity entity = type.get().create(world);
if (entity != null)
{
entity.load(entityData);
return entity;
}
}
}
catch (final RuntimeException e)
{
Log.getLogger().info("Couldn't restore entitiy", e);
return null;
}
return null;
}

/**
* Adds entities to the builder building if he needs it.
*
* @param entityData the entity info object.
* @param world the world.
* @param placer the entity placer.
* @return a list of stacks.
*/
public static List<ItemStorage> getListOfStackForEntityInfo(final CompoundTag entityData, final Level world, final Entity placer)
{
if (entityData != null)
{
final Entity entity = getEntityFromEntityInfoOrNull(entityData, world);
if (entity != null)
{
if (EntityUtils.isEntityAtPosition(entity, world, placer))
{
return Collections.emptyList();
}
return getListOfStackForEntity(entity, placer);
}
}
return Collections.emptyList();
}

/**
* Adds entities to the builder building if he needs it.
*
* @param entityData the entity info object.
* @param world the world.
* @param placer the entity placer.
* @return a list of stacks.
*/
public static List<ItemStorage> getListOfStackForEntityInfo(final CompoundTag entityData, final Level world, final AbstractEntityCitizen placer)
{
if (placer != null)
{
return getListOfStackForEntityInfo(entityData, world, (Entity) placer);
}

return Lists.newArrayList();
}

/**
* Adds entities to the builder building if he needs it.
*
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/minecolonies/core/colony/CitizenData.java
Original file line number Diff line number Diff line change
Expand Up @@ -2016,15 +2016,15 @@ public BlockPos getHomePosition()
@Nullable final IBuilding homeBuilding = getHomeBuilding();
if (homeBuilding != null)
{
return homeBuilding.getStandingPosition();
return homeBuilding.getPosition();
}

if (colony != null)
{
final IBuilding tavern = colony.getBuildingManager().getFirstBuildingMatching(b -> b.getBuildingType() == ModBuildings.tavern.get());
if (tavern != null)
{
return tavern.getStandingPosition();
return tavern.getPosition();
}
else if (colony.getBuildingManager().getTownHall() != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1046,61 +1046,6 @@ public void resetGuardBuildingNear()
this.recheckGuardBuildingNear = true;
}

@Override
public BlockPos getStandingPosition()
{
if (cachedStandingPosition == null)
{
if (!WorldUtil.isEntityBlockLoaded(colony.getWorld(), getPosition()))
{
return getPosition();
}

BlockPos bestPos = getPosition();
int bestScore = 0;

//Return true if the building is null to stall the worker
for (final Direction dir : Direction.Plane.HORIZONTAL)
{
final BlockPos currentPos = getPosition().relative(dir);
final BlockState hereState = colony.getWorld().getBlockState(currentPos);
// Check air here and air above.
if ((!hereState.getBlock().properties.hasCollision || hereState.is(BlockTags.WOOL_CARPETS))
&& !colony.getWorld().getBlockState(currentPos.above()).getBlock().properties.hasCollision
&& BlockUtils.isAnySolid(colony.getWorld().getBlockState(currentPos.below())))
{
int localScore = BEST_STANDING_SCORE;
if (colony.getWorld().canSeeSky(currentPos))
{
// More critical
localScore-=2;
}
if (colony.getWorld().getBlockState(getPosition()).getValue(AbstractBlockHut.FACING) == dir)
{
// Less critical
localScore--;
}

if (localScore == BEST_STANDING_SCORE)
{
cachedStandingPosition = currentPos;
return cachedStandingPosition;
}

if (localScore > bestScore)
{
bestScore = localScore;
bestPos = currentPos;
}
}
}

// prefer default rotation of the building facing this.
cachedStandingPosition = bestPos;
}
return cachedStandingPosition == null ? getPosition() : cachedStandingPosition;
}

//------------------------- Starting Required Tools/Item handling -------------------------//

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ public static List<BlockPos> createWaypoints(final Level world, final Path path,
{
final BlockPos point = path.getNode(i).asBlockPos();
if (lastPoint.distManhattan(point) > spacing
&& world.getBlockState(point).isAir())
&& world.getBlockState(point).isAir() && world.getBlockState(point.above()).isAir())
{
wayPoints.add(point);
lastPoint = point;
Expand Down
Loading

0 comments on commit 7c1f25e

Please sign in to comment.