User Tools

Site Tools


tutorial:villager_activities

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
tutorial:villager_activities [2023/09/13 20:30] – removed - external edit (Unknown date) 127.0.0.1tutorial:villager_activities [2023/09/13 20:30] (current) – ↷ Page moved from villager_activities to tutorial:villager_activities nebelnidas
Line 1: Line 1:
 +====== 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:
 +
 +<code java [enable_line_numbers="true"]>
 +    public static final Activity PRAY = Activity.register("pray");
 +</code>
 +
 +
 +
 +Then create a task:
 +
 +<code java [enable_line_numbers="true"]>
 +public class FindTempleTask extends Task<VillagerEntity> {
 +    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);
 +                });
 +    }
 +}
 +</code>
 +
 +This task just finds a ReligiousVillagersMod.MOSQUE_POINT:
 +
 +<code java [enable_line_numbers="true"]>
 + public static final MemoryModuleType<GlobalPos> MOSQUE_POINT = MemoryModuleType.register(
 + "mosque_point",
 + GlobalPos.CODEC
 + );
 +</code>
 +
 +The mosque point is a point of interest (like work benches, or a home):
 +
 +<code java [enable_line_numbers="true"]>
 +        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<MemoryModuleType<GlobalPos>, BiPredicate<VillagerEntity, PointOfInterestType>>()
 + .putAll(VillagerEntity.POINTS_OF_INTEREST)
 + .put(MOSQUE_POINT, (villagerEntity, pointOfInterestType) -> pointOfInterestType == BELIEVER)
 + .build());
 + }
 +</code>
 +
 +The position is saved in a memory module:
 +
 +<code java [enable_line_numbers="true"]>
 +VillagerEntityAccessor.setMemoryModules(new ImmutableList.Builder<MemoryModuleType<?>>()
 + .addAll(VillagerEntityAccessor.getMemoryModules()).add(MOSQUE_POINT).build());
 +</code>
 +
 +Once you have a task, you can create a set of tasks (aka Activity):
 +
 +<code java [enable_line_numbers="true"]>
 + public static ImmutableList<Pair<Integer, ? extends Task<? super VillagerEntity>>> 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())
 + );
 + }
 +</code>
 +
 +Then, you need to add the activity to their brain:
 +
 +
 +<code java [enable_line_numbers="true"]>
 +@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<VillagerEntity> brain, CallbackInfo info) {
 + VillagerEntity $this = (VillagerEntity) (Object) this;
 +
 + if (!$this.isBaby()) {
 + brain.setTaskList(
 + ReligiousVillagersMod.PRAY,
 + createPrayTasks(0.75F)
 + );
 + }
 + }
 +}
 +</code>
 +
 +And to their schedule:
 +
 +
 +<code java [enable_line_numbers="true"]>
 + static {
 + addScheduled();
 + }
 +
 + private static void addScheduled() {
 + ScheduleAccessor.setVillagerDefault(
 + new ScheduleBuilder(Schedule.VILLAGER_DEFAULT).withActivity(10, ReligiousVillagersMod.PRAY).build());//10 is the start time
 + }
 +</code>
 +
 +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 |}}