minecraft-src/net/minecraft/world/level/SpawnData.java
2025-07-04 03:45:38 +03:00

80 lines
3.4 KiB
Java

package net.minecraft.world.level;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.util.Optional;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.InclusiveRange;
import net.minecraft.util.random.WeightedList;
import net.minecraft.world.entity.EquipmentTable;
public record SpawnData(CompoundTag entityToSpawn, Optional<SpawnData.CustomSpawnRules> customSpawnRules, Optional<EquipmentTable> equipment) {
public static final String ENTITY_TAG = "entity";
public static final Codec<SpawnData> CODEC = RecordCodecBuilder.create(
instance -> instance.group(
CompoundTag.CODEC.fieldOf("entity").forGetter(spawnData -> spawnData.entityToSpawn),
SpawnData.CustomSpawnRules.CODEC.optionalFieldOf("custom_spawn_rules").forGetter(spawnData -> spawnData.customSpawnRules),
EquipmentTable.CODEC.optionalFieldOf("equipment").forGetter(spawnData -> spawnData.equipment)
)
.apply(instance, SpawnData::new)
);
public static final Codec<WeightedList<SpawnData>> LIST_CODEC = WeightedList.codec(CODEC);
public SpawnData() {
this(new CompoundTag(), Optional.empty(), Optional.empty());
}
public SpawnData(CompoundTag entityToSpawn, Optional<SpawnData.CustomSpawnRules> customSpawnRules, Optional<EquipmentTable> equipment) {
Optional<ResourceLocation> optional = entityToSpawn.read("id", ResourceLocation.CODEC);
if (optional.isPresent()) {
entityToSpawn.store("id", ResourceLocation.CODEC, (ResourceLocation)optional.get());
} else {
entityToSpawn.remove("id");
}
this.entityToSpawn = entityToSpawn;
this.customSpawnRules = customSpawnRules;
this.equipment = equipment;
}
public CompoundTag getEntityToSpawn() {
return this.entityToSpawn;
}
public Optional<SpawnData.CustomSpawnRules> getCustomSpawnRules() {
return this.customSpawnRules;
}
public Optional<EquipmentTable> getEquipment() {
return this.equipment;
}
public record CustomSpawnRules(InclusiveRange<Integer> blockLightLimit, InclusiveRange<Integer> skyLightLimit) {
private static final InclusiveRange<Integer> LIGHT_RANGE = new InclusiveRange(0, 15);
public static final Codec<SpawnData.CustomSpawnRules> CODEC = RecordCodecBuilder.create(
instance -> instance.group(
lightLimit("block_light_limit").forGetter(customSpawnRules -> customSpawnRules.blockLightLimit),
lightLimit("sky_light_limit").forGetter(customSpawnRules -> customSpawnRules.skyLightLimit)
)
.apply(instance, SpawnData.CustomSpawnRules::new)
);
private static DataResult<InclusiveRange<Integer>> checkLightBoundaries(InclusiveRange<Integer> lightValues) {
return !LIGHT_RANGE.contains(lightValues) ? DataResult.error(() -> "Light values must be withing range " + LIGHT_RANGE) : DataResult.success(lightValues);
}
private static MapCodec<InclusiveRange<Integer>> lightLimit(String fieldName) {
return InclusiveRange.INT.lenientOptionalFieldOf(fieldName, LIGHT_RANGE).validate(SpawnData.CustomSpawnRules::checkLightBoundaries);
}
public boolean isValidPosition(BlockPos pos, ServerLevel level) {
return this.blockLightLimit.isValueInRange(level.getBrightness(LightLayer.BLOCK, pos))
&& this.skyLightLimit.isValueInRange(level.getBrightness(LightLayer.SKY, pos));
}
}
}