Skip to content

Commit

Permalink
Add dynamic bee products
Browse files Browse the repository at this point in the history
  • Loading branch information
thedarkcolour committed Aug 10, 2024
1 parent 76a7fc2 commit e36ce7d
Show file tree
Hide file tree
Showing 37 changed files with 300 additions and 206 deletions.
6 changes: 6 additions & 0 deletions src/main/java/forestry/api/apiculture/genetics/IBee.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,14 @@ public interface IBee extends IIndividualLiving {

List<Holder.Reference<Biome>> getSuitableBiomes(Registry<Biome> registry);

/**
* @return A list of item stacks used for displaying this bee's products in the Analyzer GUI.
*/
List<ItemStack> getProduceList();

/**
* @return A list of item stacks used for displaying this bee's specialty products in the Analyzer GUI.
*/
List<ItemStack> getSpecialtyList();

List<ItemStack> produceStacks(IBeeHousing housing);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import forestry.api.apiculture.IBeeHousing;
import forestry.api.core.HumidityType;
import forestry.api.core.IProduct;
import forestry.api.core.TemperatureType;
import forestry.api.genetics.IGenome;
import forestry.api.genetics.ISpecies;
Expand All @@ -19,12 +20,12 @@ public interface IBeeSpecies extends ISpecies<IBee> {
/**
* @return The list of possible items that can be produced by this bee.
*/
List<Product> getProducts();
List<IProduct> getProducts();

/**
* @return The list of possible items that this bee can only produce when in a jubilant state.
*/
List<Product> getSpecialties();
List<IProduct> getSpecialties();

/**
* @return The preferred/ideal temperature for this bee.
Expand Down
12 changes: 3 additions & 9 deletions src/main/java/forestry/api/arboriculture/genetics/IFruit.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.event.TextureStitchEvent;

import forestry.api.core.IProduct;
import forestry.api.genetics.IGenome;
import forestry.api.core.Product;
import forestry.api.genetics.alleles.IRegistryAlleleValue;
import forestry.api.genetics.alleles.TreeChromosomes;
import forestry.core.utils.SpeciesUtil;
Expand Down Expand Up @@ -82,14 +82,14 @@ default float getFruitChance(IGenome genome, LevelAccessor level, BlockPos pos)
*
* @return A unmodifiable list that contains all products and their associated drop chances.
*/
List<Product> getProducts();
List<IProduct> getProducts();

/**
* A unmodifiable list that contains all specialties and their associated drop chances.
*
* @return A unmodifiable list that contains all products and their associated drop chances.
*/
List<Product> getSpecialty();
List<IProduct> getSpecialty();

/**
* Returns all drops of this block if you harvest it.
Expand All @@ -99,12 +99,6 @@ default float getFruitChance(IGenome genome, LevelAccessor level, BlockPos pos)
*/
List<ItemStack> getFruits(IGenome genome, Level level, BlockPos pos, int ripeningTime);

/**
* @return The location of the pod model in the "modid:pods/" folder.
*/
@Nullable
String getModelName();

/**
* @param ripeningTime Elapsed ripening time for the fruit.
* @return ResourceLocation of the texture to overlay on the leaf block.
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/forestry/api/arboriculture/genetics/ITree.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.mojang.authlib.GameProfile;

import forestry.api.arboriculture.ITreeSpecies;
import forestry.api.core.IProduct;
import forestry.api.genetics.IEffectData;
import forestry.api.genetics.IIndividual;
import forestry.api.core.Product;
Expand All @@ -30,9 +31,9 @@ public interface ITree extends IIndividual {

List<ITree> getSaplings(Level level, @Nullable GameProfile playerProfile, BlockPos pos, float modifier);

List<Product> getProducts();
List<IProduct> getProducts();

List<Product> getSpecialties();
List<IProduct> getSpecialties();

List<ItemStack> produceStacks(Level level, BlockPos pos, int ripeningTime);

Expand Down
61 changes: 61 additions & 0 deletions src/main/java/forestry/api/core/IProduct.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package forestry.api.core;

import javax.annotation.Nullable;

import net.minecraft.util.RandomSource;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;

import it.unimi.dsi.fastutil.Hash;

/**
* Represents some item that has a set chance of being produced.
*
* @see Product The default implementation used in the majority of cases.
*/
public interface IProduct {
/**
* A hashing strategy used for FastUtil custom hash collections.
* Currently, Forestry uses this to remove common products between species from the product list of a hybrid bee.
*/
Hash.Strategy<IProduct> ITEM_ONLY_STRATEGY = new Hash.Strategy<>() {
@Override
public int hashCode(@Nullable IProduct o) {
return o == null ? 0 : o.item().hashCode();
}

@Override
public boolean equals(@Nullable IProduct a, @Nullable IProduct b) {
return (a == null || b == null) ? a == b : a.item() == b.item();
}
};

// todo should this be replaced with is(ItemStack) and getIconStack() methods instead?
/**
* Gets the item this product contains. In the case of a dynamic product, return an item that might
* be used to display it in a screen or for equality purposes in {@link #ITEM_ONLY_STRATEGY}.
*
* @return The item this product represents.
*/
Item item();

/**
* @return The set chance of this product being produced.
*/
float chance();

/**
* @return A new stack of this product. If your product is dynamic, return a "default" nonempty stack.
*/
ItemStack createStack();

/**
* Used to produce a random variant of this product.
*
* @param random The random source. If no randomness is desired, call {@link #createStack} instead.
* @return A new stack of this product with potentially random properties.
*/
default ItemStack createRandomStack(RandomSource random) {
return createStack();
}
}
48 changes: 20 additions & 28 deletions src/main/java/forestry/api/core/Product.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,30 @@
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;

import it.unimi.dsi.fastutil.Hash;

public record Product(Item item, int count, @Nullable CompoundTag tag, float chance) {
// Hash for quick de-duping
public static final Hash.Strategy<Product> ITEM_ONLY_STRATEGY;
public static final Codec<Product> CODEC;
/**
* Default implementation of {@link IProduct}. Used in most cases.
*
* @param item The item this product represents.
* @param count The count the produced stack should have.
* @param tag The NBT tag
* @param chance
*/
public record Product(Item item, int count, @Nullable CompoundTag tag, float chance) implements IProduct {
public static final Codec<Product> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Registry.ITEM.byNameCodec().fieldOf("item").forGetter(Product::item),
Codec.intRange(1, 64).optionalFieldOf("count", 1).forGetter(Product::count),
CompoundTag.CODEC.optionalFieldOf("tag").forGetter(product -> Optional.ofNullable(product.tag)),
Codec.floatRange(0f, 1f).fieldOf("chance").forGetter(Product::chance)
).apply(instance, (item, count, tag, chance) -> new Product(item, count, tag.orElse(null), chance)));
// todo StreamCodec in 1.21

@Override
public ItemStack createStack() {
ItemStack stack = new ItemStack(item, count);
stack.setTag(tag);
if (this.tag != null) {
// defensive copy
stack.setTag(tag.copy());
}
return stack;
}

Expand Down Expand Up @@ -53,25 +66,4 @@ public static Product fromNetwork(FriendlyByteBuf buffer) {

return new Product(item, count, tag, chance);
}

static {
ITEM_ONLY_STRATEGY = new Hash.Strategy<>() {
@Override
public int hashCode(@Nullable Product o) {
return o == null ? 0 : o.item.hashCode();
}

@Override
public boolean equals(@Nullable Product a, @Nullable Product b) {
return (a == null || b == null) ? a == b : a.item == b.item;
}
};

CODEC = RecordCodecBuilder.create(instance -> instance.group(
Registry.ITEM.byNameCodec().fieldOf("item").forGetter(Product::item),
Codec.intRange(1, 64).optionalFieldOf("count", 1).forGetter(Product::count),
CompoundTag.CODEC.optionalFieldOf("tag").forGetter(product -> Optional.ofNullable(product.tag)),
Codec.floatRange(0f, 1f).fieldOf("chance").forGetter(Product::chance)
).apply(instance, (item, count, tag, chance) -> new Product(item, count, tag.orElse(null), chance)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@

import java.util.List;

import forestry.api.core.IProduct;
import forestry.api.core.Product;
import forestry.api.genetics.alleles.IRegistryAlleleValue;

public interface IButterflyCocoon extends IRegistryAlleleValue {
List<Product> getProducts();
List<IProduct> getProducts();
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import net.minecraft.world.level.biome.Biome;

import forestry.api.core.HumidityType;
import forestry.api.core.IProduct;
import forestry.api.core.TemperatureType;
import forestry.api.genetics.ISpecies;
import forestry.api.core.Product;
Expand Down Expand Up @@ -63,12 +64,12 @@ public interface IButterflySpecies extends ISpecies<IButterfly> {
/**
* @return The loot that drops if you kill a butterfly.
*/
List<Product> getButterflyLoot();
List<IProduct> getButterflyLoot();

/**
* @return The loot that drops if you destroy a leaf that contains a caterpillar.
*/
List<Product> getCaterpillarProducts();
List<IProduct> getCaterpillarProducts();

/**
* @return The color of this butterfly's serum item. Also used for escritoire cells.
Expand Down
34 changes: 25 additions & 9 deletions src/main/java/forestry/api/plugin/IBeeSpeciesBuilder.java
Original file line number Diff line number Diff line change
@@ -1,38 +1,54 @@
package forestry.api.plugin;

import javax.annotation.Nullable;
import java.awt.Color;
import java.util.List;
import java.util.function.Supplier;

import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;

import forestry.api.apiculture.IBeeJubilance;
import forestry.api.apiculture.genetics.IBeeSpecies;
import forestry.api.apiculture.genetics.IBeeSpeciesType;
import forestry.api.core.IProduct;
import forestry.api.core.Product;

/**
* Builder used to register new bee species and configure already existing ones.
* Use {@link IApicultureRegistration#registerSpecies} to obtain instances of this class.
*/
public interface IBeeSpeciesBuilder extends ISpeciesBuilder<IBeeSpeciesType, IBeeSpecies, IBeeSpeciesBuilder> {
/**
* Adds a product to this species.
*
* @param product A product that can be produced by this species.
*/
IBeeSpeciesBuilder addProduct(IProduct product);

/**
* Adds a product to this bee species.
*
* @param stack A supplier that creates a new instance of the result.
* @param stack The item stack the product should produce.
* @param chance A float between 0 and 1. The chance that this product is produced during a single work cycle.
*/
IBeeSpeciesBuilder addProduct(ItemStack stack, float chance);
default IBeeSpeciesBuilder addProduct(ItemStack stack, float chance) {
return addProduct(new Product(stack.getItem(), stack.getCount(), stack.getTag(), chance));
}

/**
* Adds a specialty product to this species, only produced when the bee in a jubilant state.
*
* @param specialty A product that can only be produced by this species when in its jubilant state.
*/
IBeeSpeciesBuilder addSpecialty(IProduct specialty);

/**
* Adds a specialty to the bee species, a product only produced when the bee is in a jubilant state.
*
* @param stack A supplier that creates a new instance of the result.
* @param stack The item stack the product should produce.
* @param chance A float between 0 and 1. The chance that this product is produced during a single work cycle.
*/
IBeeSpeciesBuilder addSpecialty(ItemStack stack, float chance);
default IBeeSpeciesBuilder addSpecialty(ItemStack stack, float chance) {
return addSpecialty(new Product(stack.getItem(), stack.getCount(), stack.getTag(), chance));
}

/**
* Sets the color of the bee's body. The default is yellow, {@code #ffdc16}, used by most bees.
Expand Down Expand Up @@ -60,9 +76,9 @@ public interface IBeeSpeciesBuilder extends ISpeciesBuilder<IBeeSpeciesType, IBe
*/
IBeeSpeciesBuilder setNocturnal(boolean nocturnal);

List<Product> buildProducts();
List<IProduct> buildProducts();

List<Product> buildSpecialties();
List<IProduct> buildSpecialties();

int getBody();

Expand Down
10 changes: 3 additions & 7 deletions src/main/java/forestry/api/plugin/IButterflySpeciesBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.biome.Biome;

import forestry.api.core.IProduct;
import forestry.api.core.Product;
import forestry.api.lepidopterology.genetics.IButterflySpecies;
import forestry.api.lepidopterology.genetics.IButterflySpeciesType;
Expand Down Expand Up @@ -49,11 +50,6 @@ public interface IButterflySpeciesBuilder extends ISpeciesBuilder<IButterflySpec
*/
IButterflySpeciesBuilder setRarity(float rarity);

/**
* @param texturePath String texture path for this butterfly e.g. "forestry:butterfly/..."
*/
IButterflySpeciesBuilder setTexture(String texturePath);

int getSerumColor();

float getFlightDistance();
Expand All @@ -67,7 +63,7 @@ public interface IButterflySpeciesBuilder extends ISpeciesBuilder<IButterflySpec

float getRarity();

List<Product> buildProducts();
List<IProduct> buildProducts();

List<Product> buildCaterpillarProducts();
List<IProduct> buildCaterpillarProducts();
}
9 changes: 5 additions & 4 deletions src/main/java/forestry/apiculture/BeeSpecies.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import forestry.api.apiculture.genetics.IBeeSpecies;
import forestry.api.apiculture.genetics.IBeeSpeciesType;
import forestry.api.core.HumidityType;
import forestry.api.core.IProduct;
import forestry.api.core.Product;
import forestry.api.core.TemperatureType;
import forestry.api.genetics.ClimateHelper;
Expand All @@ -27,8 +28,8 @@

public class BeeSpecies extends Species<IBeeSpeciesType, IBee> implements IBeeSpecies {
private final boolean nocturnal;
private final List<Product> products;
private final List<Product> specialties;
private final List<IProduct> products;
private final List<IProduct> specialties;
private final TemperatureType temperature;
private final HumidityType humidity;
private final IBeeJubilance jubilance;
Expand Down Expand Up @@ -56,12 +57,12 @@ public boolean isNocturnal() {
}

@Override
public List<Product> getProducts() {
public List<IProduct> getProducts() {
return this.products;
}

@Override
public List<Product> getSpecialties() {
public List<IProduct> getSpecialties() {
return this.specialties;
}

Expand Down
Loading

0 comments on commit e36ce7d

Please sign in to comment.