====== Activities ======
This is summary of how to add stuff for villagers to do. [[https://github.com/EmmanuelMess/ReligiousVillagersMinecraftMod|Here]] is the repo with the full code. The accessors are not explained here, they are at [[tutorial:mixin_accessors|Mixin Accessors]].
An activity is a set of tasks.
First register the activity:
public static final Activity PRAY = Activity.register("pray");
Then create a task:
public class FindTempleTask extends Task {
public FindTempleTask() {
super(ImmutableMap.of(ReligiousVillagersMod.MOSQUE_POINT, MemoryModuleState.VALUE_ABSENT));//Conditions to be met to start the task
}
protected boolean shouldRun(ServerWorld world, VillagerEntity entity) {
return world.getPointOfInterestStorage()
.getNearestPosition(
ReligiousVillagersMod.BELIEVER.getCompletionCondition(),
entity.getBlockPos(),
48,
PointOfInterestStorage.OccupationStatus.ANY
).isPresent();
}
protected void run(ServerWorld world, VillagerEntity entity, long time) {
ReligiousVillagersMod.LOGGER.info("FindTemple:run!");
world.getPointOfInterestStorage()
.getPositions(
ReligiousVillagersMod.BELIEVER.getCompletionCondition(),
(blockPos) -> {
Path path = entity
.getNavigation()
.findPathTo(blockPos, ReligiousVillagersMod.BELIEVER.getSearchDistance());
return (path != null && path.reachesTarget());
},
entity.getBlockPos(),
48,
PointOfInterestStorage.OccupationStatus.ANY
)
.findAny()
.ifPresent(blockPos -> {
GlobalPos globalPos = GlobalPos.create(world.getRegistryKey(), blockPos);
entity.getBrain().remember(ReligiousVillagersMod.MOSQUE_POINT, globalPos);
});
}
}
This task just finds a ReligiousVillagersMod.MOSQUE_POINT:
public static final MemoryModuleType MOSQUE_POINT = MemoryModuleType.register(
"mosque_point",
GlobalPos.CODEC
);
The mosque point is a point of interest (like work benches, or a home):
static {
public static final PointOfInterestType BELIEVER = PointOfInterestType.register(
"believer", PointOfInterestType.getAllStatesOf(Blocks.EMERALD_BLOCK), 32, 100
);
addPointsOfInterest();
}
private static void addPointsOfInterest() {
VillagerEntityAccessor.setPointsOfInterest(
new ImmutableMap.Builder, BiPredicate>()
.putAll(VillagerEntity.POINTS_OF_INTEREST)
.put(MOSQUE_POINT, (villagerEntity, pointOfInterestType) -> pointOfInterestType == BELIEVER)
.build());
}
The position is saved in a memory module:
VillagerEntityAccessor.setMemoryModules(new ImmutableList.Builder>()
.addAll(VillagerEntityAccessor.getMemoryModules()).add(MOSQUE_POINT).build());
Once you have a task, you can create a set of tasks (aka Activity):
public static ImmutableList>> createPrayTasks(float speed) {
return ImmutableList.of(
Pair.of(1, new FindTempleTask()),
Pair.of(2, new VillagerWalkTowardsTask(
MOSQUE_POINT, speed, 1, 150, 1200//info about how to do the task
)),
Pair.of(3, new ForgetCompletedPointOfInterestTask(BELIEVER, MOSQUE_POINT)),
Pair.of(3, new PrayVillagerTask()),//Another task, remove it if you dont want it.
Pair.of(99, new ScheduleActivityTask())
);
}
Then, you need to add the activity to their brain:
@Mixin(VillagerEntity.class)
public class VillagerEntityMixin {
@Inject(at = @At("HEAD"), method = "initBrain(Lnet/minecraft/entity/ai/brain/Brain;)V", locals = LocalCapture.CAPTURE_FAILEXCEPTION)
private void initBrain(Brain brain, CallbackInfo info) {
VillagerEntity $this = (VillagerEntity) (Object) this;
if (!$this.isBaby()) {
brain.setTaskList(
ReligiousVillagersMod.PRAY,
createPrayTasks(0.75F)
);
}
}
}
And to their schedule:
static {
addScheduled();
}
private static void addScheduled() {
ScheduleAccessor.setVillagerDefault(
new ScheduleBuilder(Schedule.VILLAGER_DEFAULT).withActivity(10, ReligiousVillagersMod.PRAY).build());//10 is the start time
}
If all went well and you have all the accessors, you should be able to put down an emerald block inside a village and villagers will pray before work:
{{ :unknown.png?nolink&400 |}}