package com.tiedup.remake.personality; import com.tiedup.remake.cells.CellDataV2; import com.tiedup.remake.v2.blocks.PetBedBlock; import org.jetbrains.annotations.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.BedBlock; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.CarpetBlock; /** * Quality of the cell/environment around an NPC's home. * *

Evaluated in a radius around the home position and applies * a mood modifier based on living conditions. * *

*/ public enum CellQuality { /** Bed + Carpet + Light > 10: good living conditions */ LUXURY(5.0f), /** PetBed OR Bed: normal conditions */ STANDARD(0.0f), /** No bed + Light < 5: harsh conditions */ DUNGEON(-5.0f); /** Mood modifier applied when NPC lives in this quality cell */ public final float moodModifier; CellQuality(float moodModifier) { this.moodModifier = moodModifier; } /** Detection radius around home (5 blocks) */ public static final int DETECTION_RADIUS = 5; /** Light level threshold for LUXURY (> 10) */ public static final int LIGHT_LUXURY_THRESHOLD = 10; /** Light level threshold for DUNGEON (< 5) */ public static final int LIGHT_DUNGEON_THRESHOLD = 5; /** * Evaluate cell quality around a home position, optionally using CellDataV2 features. * *

When a cell is provided, bed/pet bed detection uses pre-computed flood-fill data * instead of scanning blocks. Carpets still require a block scan since they are not * tracked by the flood-fill. * * @param homePos The home block position * @param level The world level * @param cell Optional CellDataV2 for optimized feature detection * @return Evaluated cell quality */ public static CellQuality evaluate( BlockPos homePos, Level level, @Nullable CellDataV2 cell ) { if (homePos == null || level == null) return STANDARD; boolean hasBed = false; boolean hasPetBed = false; boolean hasCarpet = false; if (cell != null) { // Use cell features (already detected by flood-fill) hasBed = !cell.getBeds().isEmpty(); hasPetBed = !cell.getPetBeds().isEmpty(); // Carpets not tracked by flood-fill, still need scan for (BlockPos pos : BlockPos.betweenClosed( homePos.offset(-DETECTION_RADIUS, -1, -DETECTION_RADIUS), homePos.offset(DETECTION_RADIUS, 0, DETECTION_RADIUS) )) { if ( level.getBlockState(pos).getBlock() instanceof CarpetBlock ) { hasCarpet = true; break; } } } else { // Fallback: full environment scan (no cell link) for (BlockPos pos : BlockPos.betweenClosed( homePos.offset(-DETECTION_RADIUS, -1, -DETECTION_RADIUS), homePos.offset(DETECTION_RADIUS, 2, DETECTION_RADIUS) )) { Block block = level.getBlockState(pos).getBlock(); if (block instanceof BedBlock) hasBed = true; if (block instanceof PetBedBlock) hasPetBed = true; if (block instanceof CarpetBlock) hasCarpet = true; // Early exit if we found all luxury requirements if (hasBed && hasCarpet) break; } } // Get light level at home position int lightLevel = level.getBrightness(LightLayer.BLOCK, homePos); // LUXURY: Bed + Carpet + Light > 10 if (hasBed && hasCarpet && lightLevel > LIGHT_LUXURY_THRESHOLD) { return LUXURY; } // DUNGEON: No bed/pet bed + Light < 5 if (!hasBed && !hasPetBed && lightLevel < LIGHT_DUNGEON_THRESHOLD) { return DUNGEON; } // STANDARD: Bed or PetBed (or medium light) return STANDARD; } /** * Evaluate cell quality around a home position. * * @param homePos The home block position * @param level The world level * @return Evaluated cell quality */ public static CellQuality evaluate(BlockPos homePos, Level level) { return evaluate(homePos, level, null); } }