160 lines
6.9 KiB
Java
160 lines
6.9 KiB
Java
package net.minecraft.world.level.biome;
|
|
|
|
import com.google.common.collect.ImmutableMap;
|
|
import com.google.common.collect.Lists;
|
|
import com.google.common.collect.Maps;
|
|
import com.mojang.logging.LogUtils;
|
|
import com.mojang.serialization.Codec;
|
|
import com.mojang.serialization.DataResult;
|
|
import com.mojang.serialization.MapCodec;
|
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Map.Entry;
|
|
import java.util.stream.Stream;
|
|
import net.minecraft.Util;
|
|
import net.minecraft.core.registries.BuiltInRegistries;
|
|
import net.minecraft.util.ExtraCodecs;
|
|
import net.minecraft.util.StringRepresentable;
|
|
import net.minecraft.util.random.Weight;
|
|
import net.minecraft.util.random.WeightedEntry;
|
|
import net.minecraft.util.random.WeightedRandomList;
|
|
import net.minecraft.world.entity.EntityType;
|
|
import net.minecraft.world.entity.MobCategory;
|
|
import org.jetbrains.annotations.Nullable;
|
|
import org.slf4j.Logger;
|
|
|
|
public class MobSpawnSettings {
|
|
private static final Logger LOGGER = LogUtils.getLogger();
|
|
private static final float DEFAULT_CREATURE_SPAWN_PROBABILITY = 0.1F;
|
|
public static final WeightedRandomList<MobSpawnSettings.SpawnerData> EMPTY_MOB_LIST = WeightedRandomList.create();
|
|
public static final MobSpawnSettings EMPTY = new MobSpawnSettings.Builder().build();
|
|
public static final MapCodec<MobSpawnSettings> CODEC = RecordCodecBuilder.mapCodec(
|
|
instance -> instance.group(
|
|
Codec.floatRange(0.0F, 0.9999999F)
|
|
.optionalFieldOf("creature_spawn_probability", 0.1F)
|
|
.forGetter(mobSpawnSettings -> mobSpawnSettings.creatureGenerationProbability),
|
|
Codec.simpleMap(
|
|
MobCategory.CODEC,
|
|
WeightedRandomList.codec(MobSpawnSettings.SpawnerData.CODEC).promotePartial(Util.prefix("Spawn data: ", LOGGER::error)),
|
|
StringRepresentable.keys(MobCategory.values())
|
|
)
|
|
.fieldOf("spawners")
|
|
.forGetter(mobSpawnSettings -> mobSpawnSettings.spawners),
|
|
Codec.simpleMap(BuiltInRegistries.ENTITY_TYPE.byNameCodec(), MobSpawnSettings.MobSpawnCost.CODEC, BuiltInRegistries.ENTITY_TYPE)
|
|
.fieldOf("spawn_costs")
|
|
.forGetter(mobSpawnSettings -> mobSpawnSettings.mobSpawnCosts)
|
|
)
|
|
.apply(instance, MobSpawnSettings::new)
|
|
);
|
|
private final float creatureGenerationProbability;
|
|
private final Map<MobCategory, WeightedRandomList<MobSpawnSettings.SpawnerData>> spawners;
|
|
private final Map<EntityType<?>, MobSpawnSettings.MobSpawnCost> mobSpawnCosts;
|
|
|
|
MobSpawnSettings(
|
|
float creatureGenerationProbability,
|
|
Map<MobCategory, WeightedRandomList<MobSpawnSettings.SpawnerData>> spawners,
|
|
Map<EntityType<?>, MobSpawnSettings.MobSpawnCost> mobSpawnCosts
|
|
) {
|
|
this.creatureGenerationProbability = creatureGenerationProbability;
|
|
this.spawners = ImmutableMap.copyOf(spawners);
|
|
this.mobSpawnCosts = ImmutableMap.copyOf(mobSpawnCosts);
|
|
}
|
|
|
|
public WeightedRandomList<MobSpawnSettings.SpawnerData> getMobs(MobCategory category) {
|
|
return (WeightedRandomList<MobSpawnSettings.SpawnerData>)this.spawners.getOrDefault(category, EMPTY_MOB_LIST);
|
|
}
|
|
|
|
@Nullable
|
|
public MobSpawnSettings.MobSpawnCost getMobSpawnCost(EntityType<?> entityType) {
|
|
return (MobSpawnSettings.MobSpawnCost)this.mobSpawnCosts.get(entityType);
|
|
}
|
|
|
|
public float getCreatureProbability() {
|
|
return this.creatureGenerationProbability;
|
|
}
|
|
|
|
public static class Builder {
|
|
private final Map<MobCategory, List<MobSpawnSettings.SpawnerData>> spawners = (Map<MobCategory, List<MobSpawnSettings.SpawnerData>>)Stream.of(
|
|
MobCategory.values()
|
|
)
|
|
.collect(ImmutableMap.toImmutableMap(mobCategory -> mobCategory, mobCategory -> Lists.newArrayList()));
|
|
private final Map<EntityType<?>, MobSpawnSettings.MobSpawnCost> mobSpawnCosts = Maps.<EntityType<?>, MobSpawnSettings.MobSpawnCost>newLinkedHashMap();
|
|
private float creatureGenerationProbability = 0.1F;
|
|
|
|
public MobSpawnSettings.Builder addSpawn(MobCategory classification, MobSpawnSettings.SpawnerData spawner) {
|
|
((List)this.spawners.get(classification)).add(spawner);
|
|
return this;
|
|
}
|
|
|
|
public MobSpawnSettings.Builder addMobCharge(EntityType<?> entityType, double charge, double energyBudget) {
|
|
this.mobSpawnCosts.put(entityType, new MobSpawnSettings.MobSpawnCost(energyBudget, charge));
|
|
return this;
|
|
}
|
|
|
|
public MobSpawnSettings.Builder creatureGenerationProbability(float probability) {
|
|
this.creatureGenerationProbability = probability;
|
|
return this;
|
|
}
|
|
|
|
public MobSpawnSettings build() {
|
|
return new MobSpawnSettings(
|
|
this.creatureGenerationProbability,
|
|
(Map<MobCategory, WeightedRandomList<MobSpawnSettings.SpawnerData>>)this.spawners
|
|
.entrySet()
|
|
.stream()
|
|
.collect(ImmutableMap.toImmutableMap(Entry::getKey, entry -> WeightedRandomList.create((List)entry.getValue()))),
|
|
ImmutableMap.copyOf(this.mobSpawnCosts)
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param energyBudget Determines the total amount of entities that can spawn in a location based on their current cost (e.g. a cost of 0.1 and a max total of 1 means at most ten entities can spawn in the given location).
|
|
* @param charge Determines the cost per entity towards the maximum spawn cap.
|
|
*/
|
|
public record MobSpawnCost(double energyBudget, double charge) {
|
|
public static final Codec<MobSpawnSettings.MobSpawnCost> CODEC = RecordCodecBuilder.create(
|
|
instance -> instance.group(
|
|
Codec.DOUBLE.fieldOf("energy_budget").forGetter(mobSpawnCost -> mobSpawnCost.energyBudget),
|
|
Codec.DOUBLE.fieldOf("charge").forGetter(mobSpawnCost -> mobSpawnCost.charge)
|
|
)
|
|
.apply(instance, MobSpawnSettings.MobSpawnCost::new)
|
|
);
|
|
}
|
|
|
|
public static class SpawnerData extends WeightedEntry.IntrusiveBase {
|
|
public static final Codec<MobSpawnSettings.SpawnerData> CODEC = RecordCodecBuilder.<MobSpawnSettings.SpawnerData>create(
|
|
instance -> instance.group(
|
|
BuiltInRegistries.ENTITY_TYPE.byNameCodec().fieldOf("type").forGetter(spawnerData -> spawnerData.type),
|
|
Weight.CODEC.fieldOf("weight").forGetter(WeightedEntry.IntrusiveBase::getWeight),
|
|
ExtraCodecs.POSITIVE_INT.fieldOf("minCount").forGetter(spawnerData -> spawnerData.minCount),
|
|
ExtraCodecs.POSITIVE_INT.fieldOf("maxCount").forGetter(spawnerData -> spawnerData.maxCount)
|
|
)
|
|
.apply(instance, MobSpawnSettings.SpawnerData::new)
|
|
)
|
|
.validate(
|
|
spawnerData -> spawnerData.minCount > spawnerData.maxCount
|
|
? DataResult.error(() -> "minCount needs to be smaller or equal to maxCount")
|
|
: DataResult.success(spawnerData)
|
|
);
|
|
public final EntityType<?> type;
|
|
public final int minCount;
|
|
public final int maxCount;
|
|
|
|
public SpawnerData(EntityType<?> type, int weight, int minCount, int maxCount) {
|
|
this(type, Weight.of(weight), minCount, maxCount);
|
|
}
|
|
|
|
public SpawnerData(EntityType<?> type, Weight weight, int minCount, int maxCount) {
|
|
super(weight);
|
|
this.type = type.getCategory() == MobCategory.MISC ? EntityType.PIG : type;
|
|
this.minCount = minCount;
|
|
this.maxCount = maxCount;
|
|
}
|
|
|
|
public String toString() {
|
|
return EntityType.getKey(this.type) + "*(" + this.minCount + "-" + this.maxCount + "):" + this.getWeight();
|
|
}
|
|
}
|
|
}
|