Skip to content

Commit

Permalink
Fix bugs in genome and codecs + implement mutation manager
Browse files Browse the repository at this point in the history
  • Loading branch information
thedarkcolour committed Aug 6, 2024
1 parent c0cc7bf commit 1b36c6c
Show file tree
Hide file tree
Showing 32 changed files with 353 additions and 265 deletions.
24 changes: 0 additions & 24 deletions src/main/java/forestry/api/genetics/ClimateHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,15 @@
package forestry.api.genetics;

import java.util.Locale;
import java.util.Set;

import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;

import forestry.api.core.ForestryError;
import forestry.api.core.HumidityType;
import forestry.api.core.IError;
import forestry.api.core.TemperatureType;
import forestry.api.core.ToleranceType;

public class ClimateHelper {
public static void addClimateErrorStates(TemperatureType temperature, HumidityType humidity,
TemperatureType baseTemp, ToleranceType tolTemp,
HumidityType baseHumid, ToleranceType tolHumid, Set<IError> errorStates) {

if (!isWithinLimits(temperature, baseTemp, tolTemp)) {
if (baseTemp.ordinal() > temperature.ordinal()) {
errorStates.add(ForestryError.TOO_COLD);
} else {
errorStates.add(ForestryError.TOO_HOT);
}
}

if (!isWithinLimits(humidity, baseHumid, tolHumid)) {
if (baseHumid.ordinal() > humidity.ordinal()) {
errorStates.add(ForestryError.TOO_ARID);
} else {
errorStates.add(ForestryError.TOO_HUMID);
}
}
}

public static int getColor(TemperatureType temperature) {
return switch (temperature) {
case ICY -> 0xe6e6fa;
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/forestry/api/genetics/IIndividual.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package forestry.api.genetics;

import javax.annotation.Nullable;
import java.util.Optional;

import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
Expand Down Expand Up @@ -44,9 +45,18 @@ public int hashCode() {

void setMate(@Nullable IGenome mate);

/**
* @return The genome of this individual's mate, or {@code null} if this individual has no mate.
*/
@Nullable
IGenome getMate();

/**
* An optional getter for {@link #getMate}. Used only for Codec purposes, prefer {@link #getMate} when possible.
* @return An optional containing this individual's mate genome, or empty if this individual has no mate.
*/
Optional<IGenome> getMateOptional();

/**
* @return {@code true} if this individual has been analyzed and a summary of its genome should be displayed in its tooltip.
*/
Expand Down Expand Up @@ -76,7 +86,7 @@ default boolean isSecret() {
* Copies this individual and all of its properties EXCEPT FOR ITS MATE.
* Override this method in subclasses to make sure all information is copied.
*
* @return An exact copy of this individual.
* @return An exact copy of this individual WITHOUT A MATE.
*/
IIndividual copy();

Expand Down
4 changes: 2 additions & 2 deletions src/main/java/forestry/api/genetics/IMutation.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ public interface IMutation<S extends ISpecies<?>> {
List<IMutationCondition> getConditions();

/**
* @return {@code true} if the passed allele is one of the alleles participating in this mutation.
* @return {@code true} if the passed species is one of the alleles participating in this mutation.
*/
boolean isPartner(ISpecies<?> allele);
boolean isPartner(ISpecies<?> species);

/**
* @return The other parent in this mutation besides the given species.
Expand Down
15 changes: 4 additions & 11 deletions src/main/java/forestry/api/genetics/IMutationManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@

import java.util.List;

import net.minecraft.Util;
import net.minecraft.util.RandomSource;

import it.unimi.dsi.fastutil.objects.ObjectArrayList;

/**
* Keeps track of mutations involving members of a certain species type.
*
Expand All @@ -29,16 +26,12 @@ public interface IMutationManager<S extends ISpecies<?>> {
List<IMutation<S>> getCombinations(S firstParent, S secondParent);

/**
* @return All mutations within the species type of this mutation manager.
* @return A shuffled list of all mutations within the species type of this mutation manager.
*/
List<IMutation<S>> getAllMutations();
List<? extends IMutation<S>> getCombinationsShuffled(S firstParent, S secondParent, RandomSource rand);

/**
* @return A shuffled list of all mutations within the species type of this mutation manager.
* @return All mutations within the species type of this mutation manager.
*/
default ObjectArrayList<? extends IMutation<S>> getAllMutations(RandomSource rand) {
ObjectArrayList<? extends IMutation<S>> mutations = new ObjectArrayList<>(getAllMutations());
Util.shuffle(mutations, rand);
return mutations;
}
List<IMutation<S>> getAllMutations();
}
10 changes: 7 additions & 3 deletions src/main/java/forestry/api/genetics/ISpeciesType.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import net.minecraft.world.level.LevelAccessor;

import com.mojang.authlib.GameProfile;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;

import forestry.api.ForestryCapabilities;
Expand Down Expand Up @@ -43,6 +44,7 @@ public interface ISpeciesType<S extends ISpecies<I>, I extends IIndividual> exte

/**
* @return The mutation manager for this species type.
* @throws IllegalStateException If not all mutations have been registered.
*/
IMutationManager<S> getMutations();

Expand Down Expand Up @@ -208,17 +210,19 @@ default boolean isMember(ItemStack stack) {
* checking if the plugin implements that interface.
*
* @param plugins The list of plugins responsible for registering species and data.
* @return The map of every species registered to this species type, which later gets passed to {@link #onSpeciesRegistered}.
* @return The map of every species registered to this species type, which later gets passed
* to {@link #onSpeciesRegistered}, and the completed mutations manager for this species type.
* @see IForestryPlugin#registerApiculture(IApicultureRegistration) for an example of what data is registered.
*/
ImmutableMap<ResourceLocation, S> handleSpeciesRegistration(List<IForestryPlugin> plugins);
Pair<ImmutableMap<ResourceLocation, S>, IMutationManager<S>> handleSpeciesRegistration(List<IForestryPlugin> plugins);

/**
* Called when all species of this type have been registered and modified.
*
* @param allSpecies The map of every species ID to its species.
* @param mutations The mutations for this species type.
*/
void onSpeciesRegistered(ImmutableMap<ResourceLocation, S> allSpecies);
void onSpeciesRegistered(ImmutableMap<ResourceLocation, S> allSpecies, IMutationManager<S> mutations);

/**
* @return This species type casted to a subclass of ISpeciesType.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@

import javax.annotation.Nullable;
import java.util.List;
import java.util.Set;

import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;

import forestry.api.core.IError;
import forestry.api.genetics.IIndividualLiving;
import forestry.api.lepidopterology.IButterflyCocoon;
import forestry.api.lepidopterology.IButterflyNursery;
Expand Down Expand Up @@ -43,26 +41,6 @@ default boolean isAcceptedEnvironment(Level level, double x, double y, double z)
@Nullable
IButterfly spawnCaterpillar(IButterflyNursery nursery);

/**
* Determines whether the caterpillar can grow.
*
* @param cocoon the {@link IButterflyCocoon} the caterpillar resides in.
* @param nursery the {@link IButterflyNursery} of the caterpillar.
* @return an empty set if the caterpillar can grow, a set of error states if the caterpillar can not grow
* @since 5.3.3
*/
Set<IError> getCanGrow(IButterflyNursery nursery, @Nullable IButterflyCocoon cocoon);

/**
* Determines whether the caterpillar can spawn. (Used to auto-spawn butterflies out of a cocoon.)
*
* @param cocoon the {@link IButterflyCocoon} the caterpillar resides in.
* @param nursery the {@link IButterflyNursery} of the caterpillar.
* @return an empty set if the caterpillar can spawn, a set of error states if the caterpillar can not spawn
* @since 5.3.3
*/
Set<IError> getCanSpawn(IButterflyNursery nursery, @Nullable IButterflyCocoon cocoon);

/**
* @param playerKill Whether or not the butterfly was killed by a player.
* @param lootLevel Loot level according to the weapon used to kill the butterfly.
Expand Down
14 changes: 12 additions & 2 deletions src/main/java/forestry/api/plugin/IMutationBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,23 @@
******************************************************************************/
package forestry.api.plugin;

import com.google.common.collect.ImmutableMap;

import java.time.Month;

import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.state.BlockState;

import forestry.api.core.HumidityType;
import forestry.api.core.TemperatureType;
import forestry.api.genetics.IMutation;
import forestry.api.genetics.IMutationCondition;
import forestry.api.genetics.ISpecies;
import forestry.api.genetics.ISpeciesType;
import forestry.api.genetics.alleles.IAllele;
import forestry.api.genetics.alleles.IChromosome;
import forestry.core.genetics.mutations.Mutation;

/**
* Set custom mutation requirements
Expand Down Expand Up @@ -85,5 +88,12 @@ default IMutationBuilder restrictDateRange(Month startMonth, int startDay, Month
*/
IMutationBuilder setChance(int chance);

<S extends ISpecies<?>> Mutation<S> build(ISpeciesType<S, ?> speciesType);
/**
* Builds the mutation. Used internally.
*
* @param speciesType Species type of the mutation. Do not call {@link ISpeciesType#getSpecies}.
* @param speciesLookup The species by ID lookup, since species type might not have the registry yet.
* @return The completed Mutation object with immutable data.
*/
<S extends ISpecies<?>> IMutation<S> build(ISpeciesType<S, ?> speciesType, ImmutableMap<ResourceLocation, S> speciesLookup);
}
6 changes: 6 additions & 0 deletions src/main/java/forestry/api/plugin/ISpeciesBuilder.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package forestry.api.plugin;

import com.google.common.collect.ImmutableMap;

import java.util.List;
import java.util.function.Consumer;

import net.minecraft.resources.ResourceLocation;

import forestry.api.core.HumidityType;
import forestry.api.core.TemperatureType;
import forestry.api.genetics.IGenome;
import forestry.api.genetics.IMutation;
import forestry.api.genetics.ISpecies;
import forestry.api.genetics.ISpeciesType;

Expand Down Expand Up @@ -103,6 +107,8 @@ public interface ISpeciesBuilder<T extends ISpeciesType<S, ?>, S extends ISpecie

ISpeciesFactory<T, S, B> createSpeciesFactory();

List<IMutation<S>> buildMutations(ISpeciesType<S, ?> speciesType, ImmutableMap<ResourceLocation, S> speciesLookup);

@FunctionalInterface
interface ISpeciesFactory<T extends ISpeciesType<S, ?>, S extends ISpecies<?>, B extends ISpeciesBuilder<T, S, B>> {
S create(ResourceLocation id, T speciesType, IGenome defaultGenome, B builder);
Expand Down
75 changes: 31 additions & 44 deletions src/main/java/forestry/apiculture/genetics/Bee.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import net.minecraft.core.BlockPos;
Expand Down Expand Up @@ -72,26 +73,23 @@ public class Bee extends IndividualLiving<IBeeSpecies, IBee, IBeeSpeciesType> im
public static final Codec<Bee> CODEC = RecordCodecBuilder.create(instance -> {
Codec<IGenome> genomeCodec = SpeciesUtil.BEE_TYPE.get().getKaryotype().getGenomeCodec();

return instance.group(
genomeCodec.fieldOf("genome").forGetter(IIndividual::getGenome),
genomeCodec.optionalFieldOf("mate", null).forGetter(IIndividual::getMate),
return IndividualLiving.livingFields(instance, genomeCodec).and(instance.group(
Codec.BOOL.fieldOf("pristine").forGetter(IBee::isPristine),
Codec.INT.optionalFieldOf("generation", 0).forGetter(IBee::getGeneration)
).apply(instance, Bee::new);
)).apply(instance, Bee::new);
});

private int generation;
private boolean pristine = true;
private int generation;

public Bee(IGenome genome) {
super(genome);
}

// for codec. other places should use setters
private Bee(IGenome genome, @Nullable IGenome mate, boolean pristine, int generation) {
super(genome);
// For codec
private Bee(IGenome genome, Optional<IGenome> mate, boolean analyzed, int health, int maxHealth, boolean pristine, int generation) {
super(genome, mate, analyzed, health, maxHealth);

this.mate = mate;
this.pristine = pristine;
this.generation = generation;
}
Expand Down Expand Up @@ -168,15 +166,6 @@ private IEffectData doFX(IBeeEffect effect, IEffectData storedData, IBeeHousing
return effect.doFX(genome, storedData, housing);
}

// / INFORMATION

/*@Override
public IBee copy() {
CompoundTag compound = new CompoundTag();
this.write(compound);
return new Bee(compound);
}*/

@Override
public boolean canSpawn() {
return mate != null;
Expand Down Expand Up @@ -216,43 +205,41 @@ public Set<IError> getCanWork(IBeeHousing housing) {
}
}

// / Check for the sky, except if in hell
if (!world.dimensionType().hasCeiling()) {//TODO: We used 'isNether' earlier not sure if 'hasCeiling' is the right replacment method
// Check for the sky, except if in hell
if (!world.dimensionType().hasCeiling()) {
if (!housing.canBlockSeeTheSky() && !canWorkUnderground(beeModifier)) {
errorStates.add(ForestryError.NO_SKY);
}
}

// / And finally climate check
IBeeSpecies species = genome.getActiveValue(BeeChromosomes.SPECIES);
{
TemperatureType actualTemperature = housing.temperature();
TemperatureType beeBaseTemperature = species.getTemperature();
ToleranceType beeToleranceTemperature = genome.getActiveValue(BeeChromosomes.TEMPERATURE_TOLERANCE);

if (!ClimateHelper.isWithinLimits(actualTemperature, beeBaseTemperature, beeToleranceTemperature)) {
if (beeBaseTemperature.ordinal() > actualTemperature.ordinal()) {
errorStates.add(ForestryError.TOO_COLD);
} else {
errorStates.add(ForestryError.TOO_HOT);
}
// And finally climate check
IBeeSpecies species = this.species;

TemperatureType actualTemperature = housing.temperature();
TemperatureType beeBaseTemperature = species.getTemperature();
ToleranceType beeToleranceTemperature = genome.getActiveValue(BeeChromosomes.TEMPERATURE_TOLERANCE);

if (!ClimateHelper.isWithinLimits(actualTemperature, beeBaseTemperature, beeToleranceTemperature)) {
if (beeBaseTemperature.ordinal() > actualTemperature.ordinal()) {
errorStates.add(ForestryError.TOO_COLD);
} else {
errorStates.add(ForestryError.TOO_HOT);
}
}

{
HumidityType actualHumidity = housing.humidity();
HumidityType beeBaseHumidity = species.getHumidity();
ToleranceType beeToleranceHumidity = genome.getActiveValue(BeeChromosomes.HUMIDITY_TOLERANCE);
HumidityType actualHumidity = housing.humidity();
HumidityType beeBaseHumidity = species.getHumidity();
ToleranceType beeToleranceHumidity = genome.getActiveValue(BeeChromosomes.HUMIDITY_TOLERANCE);

if (!ClimateHelper.isWithinLimits(actualHumidity, beeBaseHumidity, beeToleranceHumidity)) {
if (beeBaseHumidity.ordinal() > actualHumidity.ordinal()) {
errorStates.add(ForestryError.TOO_ARID);
} else {
errorStates.add(ForestryError.TOO_HUMID);
}
if (!ClimateHelper.isWithinLimits(actualHumidity, beeBaseHumidity, beeToleranceHumidity)) {
if (beeBaseHumidity.ordinal() > actualHumidity.ordinal()) {
errorStates.add(ForestryError.TOO_ARID);
} else {
errorStates.add(ForestryError.TOO_HUMID);
}
}


return errorStates;
}

Expand Down Expand Up @@ -444,7 +431,7 @@ private IBee createOffspring(IBeeHousing housing, IGenome mate, int generation)

return SpeciesUtil.createOffspring(housing.getWorldObj().random, this.genome, mate, mutator, genome -> {
//IBeekeepingMode mode = BeeManager.beeRoot.getBeekeepingMode(level);
return new Bee(genome, null, this.pristine, generation); /*mode.isOffspringPristine(this)*/
return new Bee(genome, null, false, this.health, this.maxHealth, this.pristine, generation); /*mode.isOffspringPristine(this)*/
});
}

Expand Down
Loading

0 comments on commit 1b36c6c

Please sign in to comment.