Skip to content

Commit

Permalink
yet more AI overhauling
Browse files Browse the repository at this point in the history
Move all idle-like AI routines to not doing pathing themselves, but setting a walk target, this drastically reduces the number of pathfinds needed, and more centralizes that.

This standardizes the checks for movement as well, so sleeping/frozen/etc won't walk around

Moves block and item lookups to also using a centralized AI, so that no longer needs to be looked up either

Hunger AI is more modular, so easier to add new types of blocks to try to eat, also adjustments to how it selects them

Fixes the toImmutable not being overriden for the internal mutable block pos used by vector 3s, this will fix Thuts-Mods/ThutCore#3 when it is merged over to there
  • Loading branch information
Thutmose committed May 20, 2020
1 parent 6f69e0d commit 2f1fba0
Show file tree
Hide file tree
Showing 67 changed files with 1,952 additions and 1,819 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import pokecube.adventures.capabilities.CapabilityNPCAIStates.IHasNPCAIStates;
import pokecube.adventures.capabilities.CapabilityNPCMessages.IHasMessages;
import pokecube.adventures.capabilities.TrainerCaps;
import pokecube.core.ai.tasks.AIBase.IRunnable;
import pokecube.core.ai.tasks.IRunnable;
import thut.api.entity.ai.IAIRunnable;

public class AITrainerBase implements IAIRunnable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,7 @@ public void tick()
applied = true;
this.power -= needed;
if (gainExp) pokemob.setExp(pokemob.getExp() + exp_out, true);
if (PokecubeAdv.config.dayCareBreedSpeedup) pokemob.setLoveTimer(pokemob.getLoveTimer()
+ PokecubeAdv.config.dayCareBreedAmount);
if (PokecubeAdv.config.dayCareBreedSpeedup) pokemob.tickBreedDelay(PokecubeAdv.config.dayCareBreedAmount);
}
if (applied) this.getWorld().playSound(null, this.getPos(), SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP,
SoundCategory.BLOCKS, 0.25f, 1);
Expand Down
110 changes: 109 additions & 1 deletion src/main/java/pokecube/core/ai/brain/BrainUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,19 @@
import java.util.List;
import java.util.Optional;

import net.minecraft.entity.AgeableEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.MobEntity;
import net.minecraft.entity.ai.brain.Brain;
import net.minecraft.entity.ai.brain.memory.MemoryModuleStatus;
import net.minecraft.entity.ai.brain.memory.MemoryModuleType;
import net.minecraft.entity.ai.brain.sensor.Sensor;
import net.minecraft.entity.ai.brain.sensor.SensorType;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.util.math.IPosWrapper;
import pokecube.core.ai.brain.sensors.NearBlocks.NearBlock;
import thut.api.entity.ai.VectorPosWrapper;
import thut.api.maths.Vector3;

public class BrainUtils
{
Expand All @@ -34,14 +40,116 @@ public static void setAttackTarget(final LivingEntity mobIn, final LivingEntity
if (mobIn instanceof MobEntity) ((MobEntity) mobIn).setAttackTarget(target);
}

public static void setHuntTarget(final LivingEntity mobIn, final LivingEntity target)
{
Brain<?> brain = mobIn.getBrain();
if (brain.hasMemory(MemoryModules.HUNTTARGET, MemoryModuleStatus.REGISTERED)) brain.setMemory(
MemoryModules.HUNTTARGET, target);
BrainUtils.setAttackTarget(mobIn, target);
if (target != null)
{
brain = target.getBrain();
if (brain.hasMemory(MemoryModules.HUNTED_BY, MemoryModuleStatus.REGISTERED)) brain.setMemory(
MemoryModules.HUNTED_BY, mobIn);
}
}

public static LivingEntity getHuntTarget(final LivingEntity mobIn)
{
final Brain<?> brain = mobIn.getBrain();
if (brain.hasMemory(MemoryModules.ATTACKTARGET)) return brain.getMemory(MemoryModules.ATTACKTARGET).get();
if (brain.hasMemory(MemoryModules.HUNTTARGET)) return brain.getMemory(MemoryModules.HUNTTARGET).get();
else if (mobIn instanceof MobEntity) return ((MobEntity) mobIn).getAttackTarget();
else return null;
}

public static boolean hasHuntTarget(final LivingEntity mobIn)
{
return BrainUtils.getHuntTarget(mobIn) != null;
}

public static AgeableEntity getMateTarget(final AgeableEntity mobIn)
{
final Brain<?> brain = mobIn.getBrain();
if (brain.hasMemory(MemoryModules.MATE_TARGET)) return brain.getMemory(MemoryModules.MATE_TARGET).get();
else return null;
}

public static boolean hasMateTarget(final AgeableEntity mobIn)
{
return BrainUtils.getMateTarget(mobIn) != null;
}

public static void setMateTarget(final AgeableEntity mobIn, final AgeableEntity target)
{
final Brain<?> brain = mobIn.getBrain();
if (brain.hasMemory(MemoryModules.MATE_TARGET, MemoryModuleStatus.REGISTERED)) brain.setMemory(
MemoryModules.MATE_TARGET, target);
}

public static void lookAt(final LivingEntity entityIn, final double x, final double y, final double z)
{
BrainUtils.lookAt(entityIn, Vector3.getNewVector().set(x, y, z));
}

public static void lookAt(final LivingEntity entityIn, final Vector3 vec)
{
entityIn.getBrain().setMemory(MemoryModuleType.LOOK_TARGET, new VectorPosWrapper(vec));
}

public static void setMoveUseTarget(final LivingEntity mobIn, final Vector3 pos)
{
BrainUtils.setMoveUseTarget(mobIn, new VectorPosWrapper(pos));
}

public static void setMoveUseTarget(final LivingEntity mobIn, final IPosWrapper pos)
{
final Brain<?> brain = mobIn.getBrain();
brain.setMemory(MemoryModules.MOVE_TARGET, pos);
}

public static void clearMoveUseTarget(final LivingEntity mobIn)
{
final Brain<?> brain = mobIn.getBrain();
brain.removeMemory(MemoryModules.MOVE_TARGET);
}

public static boolean hasMoveUseTarget(final LivingEntity mobIn)
{
return BrainUtils.getMoveUseTarget(mobIn) != null;
}

public static IPosWrapper getMoveUseTarget(final LivingEntity mobIn)
{
final Brain<?> brain = mobIn.getBrain();
final Optional<IPosWrapper> pos = brain.getMemory(MemoryModules.MOVE_TARGET);
if (pos == null || !pos.isPresent()) return null;
return pos.get();
}

public static List<NearBlock> getNearBlocks(final LivingEntity mobIn)
{
final Brain<?> brain = mobIn.getBrain();
final Optional<List<NearBlock>> pos = brain.getMemory(MemoryModules.VISIBLE_BLOCKS);
if (pos == null || !pos.isPresent()) return null;
return pos.get();
}

public static List<ItemEntity> getNearItems(final LivingEntity mobIn)
{
final Brain<?> brain = mobIn.getBrain();
final Optional<List<ItemEntity>> pos = brain.getMemory(MemoryModules.VISIBLE_ITEMS);
if (pos == null || !pos.isPresent()) return null;
return pos.get();
}

public static List<AgeableEntity> getMates(final AgeableEntity entity)
{
final Brain<?> brain = entity.getBrain();
final Optional<List<AgeableEntity>> pos = brain.getMemory(MemoryModules.POSSIBLE_MATES);
if (pos == null || !pos.isPresent()) return null;
return pos.get();
}

public static void addToBrain(final Brain<?> brain, final List<MemoryModuleType<?>> MEMORY_TYPES,
final List<SensorType<?>> SENSOR_TYPES)
{
Expand Down
30 changes: 28 additions & 2 deletions src/main/java/pokecube/core/ai/brain/MemoryModules.java
Original file line number Diff line number Diff line change
@@ -1,27 +1,53 @@
package pokecube.core.ai.brain;

import java.util.List;
import java.util.Optional;

import net.minecraft.entity.AgeableEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.brain.memory.MemoryModuleType;
import net.minecraft.entity.ai.brain.memory.WalkTarget;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.pathfinding.Path;
import net.minecraft.util.math.IPosWrapper;
import net.minecraftforge.event.RegistryEvent.Register;
import pokecube.core.PokecubeCore;
import pokecube.core.ai.brain.sensors.NearBlocks.NearBlock;

public class MemoryModules
{
// Used for combat
public static final MemoryModuleType<LivingEntity> ATTACKTARGET = new MemoryModuleType<>(Optional.empty());
public static final MemoryModuleType<LivingEntity> HUNTTARGET = new MemoryModuleType<>(Optional.empty());
public static final MemoryModuleType<IPosWrapper> MOVE_TARGET = new MemoryModuleType<>(Optional.empty());
public static final MemoryModuleType<LivingEntity> HUNTED_BY = new MemoryModuleType<>(Optional.empty());

// Used for pathing
public static final MemoryModuleType<Path> PATH = MemoryModuleType.PATH;
public static final MemoryModuleType<WalkTarget> WALK_TARGET = MemoryModuleType.WALK_TARGET;
public static final MemoryModuleType<Path> PATH = MemoryModuleType.PATH;
public static final MemoryModuleType<WalkTarget> WALK_TARGET = MemoryModuleType.WALK_TARGET;
public static final MemoryModuleType<Long> NOT_FOUND_PATH = MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE;

// Misc
public static final MemoryModuleType<IPosWrapper> LOOK_TARGET = MemoryModuleType.LOOK_TARGET;

public static final MemoryModuleType<List<NearBlock>> VISIBLE_BLOCKS = new MemoryModuleType<>(Optional.empty());
public static final MemoryModuleType<List<ItemEntity>> VISIBLE_ITEMS = new MemoryModuleType<>(Optional.empty());

public static final MemoryModuleType<List<AgeableEntity>> POSSIBLE_MATES = new MemoryModuleType<>(Optional.empty());
public static final MemoryModuleType<AgeableEntity> MATE_TARGET = new MemoryModuleType<>(Optional.empty());

public static void register(final Register<MemoryModuleType<?>> event)
{
event.getRegistry().register(MemoryModules.ATTACKTARGET.setRegistryName(PokecubeCore.MODID, "attack_target"));
event.getRegistry().register(MemoryModules.HUNTTARGET.setRegistryName(PokecubeCore.MODID, "hunt_target"));
event.getRegistry().register(MemoryModules.HUNTED_BY.setRegistryName(PokecubeCore.MODID, "hunted_by"));
event.getRegistry().register(MemoryModules.MOVE_TARGET.setRegistryName(PokecubeCore.MODID, "move_target"));

event.getRegistry().register(MemoryModules.VISIBLE_BLOCKS.setRegistryName(PokecubeCore.MODID,
"visible_blocks"));
event.getRegistry().register(MemoryModules.VISIBLE_ITEMS.setRegistryName(PokecubeCore.MODID, "visible_items"));

event.getRegistry().register(MemoryModules.POSSIBLE_MATES.setRegistryName(PokecubeCore.MODID, "mate_options"));
event.getRegistry().register(MemoryModules.MATE_TARGET.setRegistryName(PokecubeCore.MODID, "mate_choice"));
}
}
11 changes: 10 additions & 1 deletion src/main/java/pokecube/core/ai/brain/Sensors.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,22 @@

import net.minecraft.entity.ai.brain.sensor.SensorType;
import net.minecraftforge.event.RegistryEvent.Register;
import pokecube.core.PokecubeCore;
import pokecube.core.ai.brain.sensors.NearBlocks;
import pokecube.core.ai.brain.sensors.NearItems;
import pokecube.core.ai.brain.sensors.PossibleMates;

public class Sensors
{
public static final SensorType<NearBlocks> VISIBLE_BLOCKS = new SensorType<>(NearBlocks::new);
public static final SensorType<NearItems> VISIBLE_ITEMS = new SensorType<>(NearItems::new);
public static final SensorType<PossibleMates> VALID_MATES = new SensorType<>(PossibleMates::new);

public static void register(final Register<SensorType<?>> event)
{

event.getRegistry().register(Sensors.VISIBLE_BLOCKS.setRegistryName(PokecubeCore.MODID, "visible_blocks"));
event.getRegistry().register(Sensors.VISIBLE_ITEMS.setRegistryName(PokecubeCore.MODID, "visible_items"));
event.getRegistry().register(Sensors.VALID_MATES.setRegistryName(PokecubeCore.MODID, "valid_mates"));
}

}
100 changes: 100 additions & 0 deletions src/main/java/pokecube/core/ai/brain/sensors/NearBlocks.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package pokecube.core.ai.brain.sensors;

import java.util.List;
import java.util.Set;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;

import net.minecraft.block.BlockState;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.brain.Brain;
import net.minecraft.entity.ai.brain.memory.MemoryModuleType;
import net.minecraft.entity.ai.brain.sensor.Sensor;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.server.ServerWorld;
import pokecube.core.ai.brain.BrainUtils;
import pokecube.core.ai.brain.MemoryModules;
import thut.api.maths.Cruncher;
import thut.api.maths.Vector3;

public class NearBlocks extends Sensor<LivingEntity>
{
public static class NearBlock
{
private final BlockState state;
private final BlockPos pos;

public NearBlock(final BlockState state, final BlockPos pos)
{
this.state = state;
this.pos = pos;
}

public BlockPos getPos()
{
return this.pos;
}

public BlockState getState()
{
return this.state;
}
}

private static final int[][] indexArr = new int[32 * 32 * 32][3];

static
{
final Vector3 r = Vector3.getNewVector();
for (int i = 0; i < NearBlocks.indexArr.length; i++)
{
Cruncher.indexToVals(i, r);
if (Math.abs(r.y) <= 4)
{
NearBlocks.indexArr[i][0] = r.intX();
NearBlocks.indexArr[i][1] = r.intY();
NearBlocks.indexArr[i][2] = r.intZ();
}
else NearBlocks.indexArr[i] = null;
}
}

long lastUpdate = 0;

@Override
protected void update(final ServerWorld worldIn, final LivingEntity entityIn)
{
if (BrainUtils.hasAttackTarget(entityIn)) return;
if (BrainUtils.hasMoveUseTarget(entityIn)) return;

final Vector3 r = Vector3.getNewVector(), rAbs = Vector3.getNewVector();
final Vector3 origin = Vector3.getNewVector();
origin.set(entityIn);
final List<NearBlock> list = Lists.newArrayList();
final int size = 8;
for (int i = 0; i < size * size * size; i++)
{
final int[] pos = NearBlocks.indexArr[i];
if (pos == null) continue;
r.set(pos);
rAbs.set(r).addTo(origin);
if (rAbs.isAir(worldIn)) continue;
final BlockPos bpos = new BlockPos(rAbs.getPos());
final BlockState state = worldIn.getBlockState(bpos);
list.add(new NearBlock(state, bpos));
}
final BlockPos o0 = entityIn.getPosition();
list.sort((o1, o2) -> (int) (o1.getPos().distanceSq(o0) - o1.getPos().distanceSq(o0)));
final Brain<?> brain = entityIn.getBrain();
if (!list.isEmpty()) brain.setMemory(MemoryModules.VISIBLE_BLOCKS, list);
else brain.removeMemory(MemoryModules.VISIBLE_BLOCKS);
}

@Override
public Set<MemoryModuleType<?>> getUsedMemories()
{
return ImmutableSet.of(MemoryModules.VISIBLE_BLOCKS);
}

}
41 changes: 41 additions & 0 deletions src/main/java/pokecube/core/ai/brain/sensors/NearItems.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package pokecube.core.ai.brain.sensors;

import java.util.Comparator;
import java.util.List;
import java.util.Set;

import com.google.common.collect.ImmutableSet;

import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.brain.Brain;
import net.minecraft.entity.ai.brain.memory.MemoryModuleType;
import net.minecraft.entity.ai.brain.sensor.Sensor;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.world.server.ServerWorld;
import pokecube.core.ai.brain.MemoryModules;

public class NearItems extends Sensor<LivingEntity>
{
long lastUpdate = 0;

@Override
protected void update(final ServerWorld worldIn, final LivingEntity entityIn)
{
final List<ItemEntity> list = worldIn.getEntitiesWithinAABB(ItemEntity.class, entityIn.getBoundingBox().grow(
16.0D, 16.0D, 16.0D), (item) ->
{
return item.isAlive() && entityIn.canEntityBeSeen(item);
});
list.sort(Comparator.comparingDouble(entityIn::getDistanceSq));
final Brain<?> brain = entityIn.getBrain();
if (!list.isEmpty()) brain.setMemory(MemoryModules.VISIBLE_ITEMS, list);
else brain.removeMemory(MemoryModules.VISIBLE_ITEMS);
}

@Override
public Set<MemoryModuleType<?>> getUsedMemories()
{
return ImmutableSet.of(MemoryModules.VISIBLE_ITEMS);
}

}
Loading

0 comments on commit 2f1fba0

Please sign in to comment.