Jump to content
View in the app

A better way to browse. Learn more.

Forge Forums

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (โ‹ฎ) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Featured Replies

Posted

I'm trying to check the blocks of nearby chunks in the spawn predicate of a mob I'm making. Currently, the predicate looks something like this:

 public static boolean checkMyMobSpawnRules(EntityType<? extends MyMob> entityType, ServerLevelAccessor serverLevelAccessor, MobSpawnType mobSpawnType, BlockPos blockPos, Random random) {
   ServerLevel level = serverLevelAccessor.getLevel();
   LevelChunk chunkAtPos = level.getChunkAt(blockPos);
   List<Block> blocks = chunkAtPos.getBlockEntities().values().stream().map(entity -> entity.getBlockState().getBlock()).toList();
   // Do stuff with blocks
 }

When I debug this code, I I noticed that chunkAtPos.getBlockEntities() returns a List with size 0. Since my predicate involves checking nearby blocks, this causes my predicate to always return false. Is there a better way to get the blocks in a chunk?

  • Author

It's in a subclass of Monster. I pass a reference to this method to SpawnPlacements.register, which gets called in an event subscriber like the following:

@Mod.EventBusSubscriber(modid = Main.MOD_ID, bus = Bus.MOD)
public class ModEvents {
    private ModEvents() {
    }

    @SubscribeEvent
    public static void commonSetup(FMLCommonSetupEvent event) {
        event.enqueueWork(() -> SpawnPlacements.register(ModEntities.MY_MOB.get(), SpawnPlacements.Type.ON_GROUND, Heightmap.Types.WORLD_SURFACE, MyMob::checkMyMobSpawnRules));
    }
}

ย 

  • Author

I figure I may as well give the whole spawn predicate:

public static boolean checkMyMobSpawnRules(EntityType<? extends MyMob> entityType, ServerLevelAccessor serverLevelAccessor, MobSpawnType mobSpawnType, BlockPos blockPos, Random random) {
        ServerLevel level = serverLevelAccessor.getLevel();
        LevelChunk chunkAtPos = level.getChunkAt(blockPos);

	// check 5x5 grid of chunks for crops, centered at chunkAtPos
        boolean nearbyChunkHasCrop = Stream.of(
                Utils.getBlocksFromChunk(chunkAtPos),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.east(16))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.west(16))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.north(16))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.south(16))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.east(16).north(16))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.east(16).south(16))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.west(16).north(16))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.west(16).south(16))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.north(32))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.north(32).east(16))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.north(32).east(32))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.north(32).west(16))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.north(32).west(32))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.south(32))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.south(32).east(16))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.south(32).east(32))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.south(32).west(16))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.south(32).west(32))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.east(32))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.east(32).north(16))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.east(32).south(16))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.west(32))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.west(32).north(16))),
                Utils.getBlocksFromChunk(level.getChunkAt(blockPos.west(32).south(16)))
        ).flatMap(stream -> stream).anyMatch(block -> block instanceof CropBlock);

        boolean notUndergroundOrIndoors = true;
        for (int y = blockPos.getY() + 1; y < 320; ++y) {
            BlockEntity blockEntity = chunkAtPos.getBlockEntity(new BlockPos(blockPos.getX(), y, blockPos.getZ()));
            if (blockEntity != null) {
                Block block = blockEntity.getBlockState().getBlock();
                if (!(block instanceof AirBlock || block instanceof LeavesBlock)) {
                    notUndergroundOrIndoors = false;
                    break;
                }
            }
        }

        return Monster.checkAnyLightMonsterSpawnRules(entityType, serverLevelAccessor, mobSpawnType, blockPos, random) && notUndergroundOrIndoors && nearbyChunkHasCrop;
    }

The Utils function that gets called is the following:

public static Stream<Block> getBlocksFromChunk(LevelChunk chunk) {
        return chunk.getBlockEntities().values().stream().map(entity -> entity.getBlockState().getBlock());
    }

ย 

Edited by yeetsche420

  • Author

The subscriber maybe, but the when I was debugging the predicate I was hitting the breakpoint after world gen.

  • Author

I figured it out. I'll post what I did in case anyone else is doing something similar to what I'm doing. My predicate code is the same with the exception that chunks are retrieved with serverLevelAccessor.getChunk instead of level.getChunkAt. My utility function for getting the blocks from a chunk is the following:

public static Stream<Block> getBlocksFromChunk(ChunkAccess chunk) {
    if (chunk instanceof LevelChunk levelChunk) {
      List<Block> blocks = new ArrayList<>();
      Arrays.stream(levelChunk.getSections()).forEach(section -> section.getStates().getAll(blockState -> blocks.add(blockState.getBlock())));
      return blocks.stream();
    }
    else {
      return Stream.empty();
    }
}

ย 

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

Important Information

By using this site, you agree to our Terms of Use.

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions โ†’ Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.