Skip to content

Commit

Permalink
feat: add bulk Digestion of items in Gastric Acid
Browse files Browse the repository at this point in the history
  • Loading branch information
kd8lvt authored Oct 11, 2024
1 parent 9b54ec0 commit aba3a91
Show file tree
Hide file tree
Showing 13 changed files with 223 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public void registerParticles() {
addParticle(ModParticleTypes.LIGHT_GREEN_GLOW, "minecraft:glow");
addParticle(ModParticleTypes.HOSTILE, "biomancy:hostile");
addParticle(ModParticleTypes.BIOHAZARD, "biomancy:biohazard");
addParticle(ModParticleTypes.ACID_BUBBLE, "biomancy:acid_bubble");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ private void addBiomancyTags() {
.addTag(Tags.Items.ARMORS, Tags.Items.TOOLS)
.addTag(Tags.Items.ORES_NETHERITE_SCRAP, Tags.Items.INGOTS_NETHERITE, Tags.Items.STORAGE_BLOCKS_NETHERITE)
.addTag(forgeTag("shulker_boxes"));

createTag(ModItemTags.CANNOT_BE_DIGESTED_IN_ACID)
.add(ModItems.NUTRIENT_PASTE.get())
.add(ModItems.NUTRIENT_BAR.get())
.add(ModItems.LIVING_FLESH.get());
}

private void addMinecraftTags() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"textures": [
"biomancy:acid_bubble"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"values": [
"biomancy:nutrient_paste",
"biomancy:nutrient_bar",
"biomancy:living_flesh"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,18 @@ public Particle createParticle(SimpleParticleType type, ClientLevel level, doubl
}
}

@OnlyIn(Dist.CLIENT)
public static class AcidBubbleProvider implements ParticleProvider<SimpleParticleType> {
protected final SpriteSet sprite;

public AcidBubbleProvider(SpriteSet sprites) {
sprite = sprites;
}

public Particle createParticle(SimpleParticleType type, ClientLevel level, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed) {
VanillaDripParticle.AcidBubbleParticle particle = new VanillaDripParticle.AcidBubbleParticle(level, x, y, z, xSpeed, ySpeed, zSpeed);
particle.pickSprite(sprite);
return particle;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.github.elenterius.biomancy.client.particle;

import com.github.elenterius.biomancy.init.ModFluids;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.particle.ParticleRenderType;
import net.minecraft.client.particle.TextureSheetParticle;
Expand Down Expand Up @@ -188,4 +189,40 @@ protected void postMoveUpdate() {
}
}

@OnlyIn(Dist.CLIENT)
protected static class AcidBubbleParticle extends TextureSheetParticle { //Almost an exact copy of the vanilla BubbleParticle because it can't be extended
AcidBubbleParticle(ClientLevel level, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed) {
super(level, x, y, z);
this.setSize(0.02F, 0.02F);
this.quadSize *= this.random.nextFloat() * 0.6F + 0.2F;
this.xd = xSpeed * (double)0.2F + (Math.random() * 2.0D - 1.0D) * (double)0.02F;
this.yd = ySpeed * (double)0.2F + (Math.random() * 2.0D - 1.0D) * (double)0.02F;
this.zd = zSpeed * (double)0.2F + (Math.random() * 2.0D - 1.0D) * (double)0.02F;
this.lifetime = (int)(8.0D / (Math.random() * 0.8D + 0.2D));
}

public void tick() {
this.xo = this.x;
this.yo = this.y;
this.zo = this.z;
if (this.lifetime-- <= 0) {
this.remove();
} else {
this.yd += 0.002D;
this.move(this.xd, this.yd, this.zd);
this.xd *= 0.85F;
this.yd *= 0.85F;
this.zd *= 0.85F;
if (!this.level.getFluidState(BlockPos.containing(this.x, this.y, this.z)).is(ModFluids.ACID.get())) {
this.remove();
}

}
}

public ParticleRenderType getRenderType() {
return ParticleRenderType.PARTICLE_SHEET_OPAQUE;
}
}

}
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
package com.github.elenterius.biomancy.init;

import com.github.elenterius.biomancy.block.digester.DigesterBlockEntity;
import com.github.elenterius.biomancy.crafting.recipe.DigestingRecipe;
import com.github.elenterius.biomancy.init.tags.ModBlockTags;
import com.github.elenterius.biomancy.init.tags.ModItemTags;
import com.github.elenterius.biomancy.inventory.BehavioralInventory;
import com.github.elenterius.biomancy.util.CombatUtil;
import net.minecraft.core.Direction;
import net.minecraft.core.cauldron.CauldronInteraction;
import net.minecraft.core.dispenser.DefaultDispenseItemBehavior;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.stats.Stats;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ItemUtils;
Expand All @@ -29,6 +38,7 @@

import java.util.Map;
import java.util.Objects;
import java.util.Optional;

public final class AcidInteractions {

Expand Down Expand Up @@ -157,4 +167,85 @@ else if (livingEntity.tickCount % 10 == 0 && livingEntity.getRandom().nextFloat(
}
}

public static final class InWorldItemDigesting {
//NBT Tag keys
public static final String BASE_DATA_KEY = "biomancy:acid_digestion";
public static final String TIMER_KEY = "timer";
public static final String RECIPE_KEY = "recipe";
//Balancing multiplier applied to the output of any found recipes.
public static final double EFFICIENCY = 0.8;
//How many times tryDigestSubmergedItem should be called on a digestible item before it is processed.
//This is not directly ticks, as submerged items are only actually processed every 10 ticks.
public static final int DELAY = 10;

public static void tryDigestSubmergedItem(ItemEntity itemEntity) {
if (!digestible(itemEntity)) return;
ItemStack stack = itemEntity.getItem();
CompoundTag entityData = itemEntity.getPersistentData();
CompoundTag digestionData = getOrCreateDigestionData(entityData);
if (itemEntity.level().isClientSide && digestionData.getInt(TIMER_KEY) > 0) {
Vec3 pos = itemEntity.position();
RandomSource random = itemEntity.level().getRandom();
itemEntity.level().addParticle(ModParticleTypes.ACID_BUBBLE.get(),pos.x,pos.y,pos.z,random.nextGaussian()/100,Math.abs(random.nextGaussian()/50),random.nextGaussian()/100);
itemEntity.level().addParticle(ParticleTypes.SMOKE,pos.x,pos.y,pos.z,random.nextGaussian()/100,Math.abs(random.nextGaussian()/100),random.nextGaussian()/100);
return;
}

if (itemEntity.getAge() % 10 != 0) return; //Only tick digestion every 10 ticks.
Optional<DigestingRecipe> optionalRecipe = getDigestionRecipe(itemEntity, stack, digestionData);

if (optionalRecipe.isEmpty()) return;
if (optionalRecipe.get().getId() != ResourceLocation.tryParse(digestionData.getString(RECIPE_KEY))) {
digestionData.putString(RECIPE_KEY, optionalRecipe.get().getId().toString());
}

int currentDigestionTime = digestionData.getInt(TIMER_KEY);
if (currentDigestionTime < DELAY) {
digestionData.putInt(TIMER_KEY, currentDigestionTime + 1);
entityData.put(BASE_DATA_KEY,digestionData);
} else {
digestIntoNutrientPasteStacks(itemEntity, optionalRecipe.get());
itemEntity.getPersistentData().remove(BASE_DATA_KEY);
}
}

public static CompoundTag getOrCreateDigestionData(CompoundTag entityData) {
if (entityData.contains(BASE_DATA_KEY)) return entityData.getCompound(BASE_DATA_KEY);
return new CompoundTag();
}

public static void digestIntoNutrientPasteStacks(ItemEntity itemEntity, DigestingRecipe recipe) {
BehavioralInventory<?> tempInventory = BehavioralInventory.createServerContents(1, player -> false, () -> {});
tempInventory.insertItemStack(itemEntity.getItem());
ItemStack resultStack = recipe.assemble(tempInventory, itemEntity.level().registryAccess());
int totalToOutput = (int) Math.floor(resultStack.getCount() * itemEntity.getItem().getCount() * EFFICIENCY);
if (totalToOutput > 64) totalToOutput = splitIntoStacks(itemEntity, totalToOutput);
itemEntity.setItem(new ItemStack(ModItems.NUTRIENT_PASTE.get(), totalToOutput));
itemEntity.playSound(SoundEvents.PLAYER_BURP);
}

public static int splitIntoStacks(ItemEntity itemEntity, int numToSplit) {
Level level = itemEntity.level();
while (numToSplit > 64) {
DefaultDispenseItemBehavior.spawnItem(level, new ItemStack(ModItems.NUTRIENT_PASTE.get(), 64), 1, Direction.UP, itemEntity.position());
numToSplit -= 64;
}
return numToSplit;
}

@SuppressWarnings("RedundantIfStatement") //Let me write readable code please, thanks
public static boolean digestible(ItemEntity itemEntity) {
if (!itemEntity.isInFluidType(ModFluids.ACID_TYPE.get()) && !itemEntity.level().getBlockState(itemEntity.blockPosition()).is(ModBlocks.ACID_CAULDRON.get())) return false;
if (itemEntity.getItem().is(ModItemTags.CANNOT_BE_DIGESTED_IN_ACID)) return false;
return true;
}

private static Optional<DigestingRecipe> getDigestionRecipe(ItemEntity itemEntity, ItemStack stack, CompoundTag digestionData) {
Optional<DigestingRecipe> recipe = Optional.empty();
ResourceLocation lastRecipeId = ResourceLocation.tryParse(digestionData.getString(RECIPE_KEY));
if (lastRecipeId != null) recipe = DigesterBlockEntity.RECIPE_TYPE.get().getRecipeById(itemEntity.level(), lastRecipeId);
if (recipe.isEmpty()) recipe = DigesterBlockEntity.RECIPE_TYPE.get().getRecipeForIngredient(itemEntity.level(), stack);
return recipe; //If it's still empty, there's no recipe that matches the item stack.
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public final class ModParticleTypes {
public static final RegistryObject<SimpleParticleType> LIGHT_GREEN_GLOW = register("light_green_glow", false);
public static final RegistryObject<SimpleParticleType> HOSTILE = register("hostile", false);
public static final RegistryObject<SimpleParticleType> BIOHAZARD = register("biohazard", false);
public static final RegistryObject<SimpleParticleType> ACID_BUBBLE = register("acid_bubble", false);

private ModParticleTypes() {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ public static void registerParticles(final RegisterParticleProvidersEvent event)
event.registerSpriteSet(ModParticleTypes.LIGHT_GREEN_GLOW.get(), sprites -> new CustomGlowParticle.TwoColorProvider(sprites, 0x53ff53, 0x64e986));
event.registerSpriteSet(ModParticleTypes.HOSTILE.get(), CustomGlowParticle.GenericProvider::new);
event.registerSpriteSet(ModParticleTypes.BIOHAZARD.get(), sprites -> new CustomGlowParticle.TwoColorProvider(sprites, 0xab274f, 0x7e2a43));
event.registerSpriteSet(ModParticleTypes.ACID_BUBBLE.get(), ParticleProviders.AcidBubbleProvider::new);
}

@SubscribeEvent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public final class ModItemTags {

public static final TagKey<Item> SUGARS = tag("sugars");

public static final TagKey<Item> CANNOT_BE_DIGESTED_IN_ACID = tag("cannot_be_digested_in_acid");

private ModItemTags() {}

private static TagKey<Item> tag(String name) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.github.elenterius.biomancy.mixin;

import com.github.elenterius.biomancy.init.AcidInteractions;
import net.minecraft.world.entity.item.ItemEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(ItemEntity.class)
public abstract class ItemEntityMixin {
@Inject(at=@At("TAIL"),method={"tick()V"})
private void onTick(CallbackInfo ci) {
ItemEntity itemEntity = (ItemEntity)((Object)this); //I hate casting like this on so many levels -Kd
if (itemEntity.isRemoved()) return;
AcidInteractions.InWorldItemDigesting.tryDigestSubmergedItem(itemEntity);
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 41 additions & 7 deletions src/main/resources/mixins.biomancy.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,47 @@
"defaultRequire": 1
},
"mixins": [
"AnimalMixin", "AreaEffectCloudMixin", "ArrowMixin", "BlockMixin", "ChickenMixin", "CowMixin", "FlowingFluidMixin", "LivingEntityMixin",
"MobEffectInstanceMixin", "NodeEvaluatorMixin", "PhantomMixin", "PigMixin", "PlayerMixin", "ServerGamePacketListenerImplMixin", "ServerLevelMixin",
"SheepMixin", "SignBlockEntityMixin", "ThrownPotionMixin", "UnbreakingEnchantmentMixin", "VillagerMakeLoveMixin", "VillagerMixin", "WallBlockMixin",
"accessor.AgeableMobAccessor", "accessor.ArmorStandAccessor", "accessor.BiomeAccessor", "accessor.CreeperAccessor", "accessor.DamageSourceAccessor",
"accessor.EntityAccessor", "accessor.IntegerPropertyAccessor", "accessor.LivingEntityAccessor", "accessor.MobEffectInstanceAccessor",
"accessor.MobEntityAccessor", "accessor.ServerLevelAccessor", "accessor.SheepAccessor", "accessor.SlimeAccessor", "accessor.SuspiciousStewItemAccessor",
"accessor.SwordItemMixinAccessor", "accessor.TadpoleAccessor", "accessor.TextureSlotAccessor", "accessor.ZombieVillagerMixinAccessor"
"AnimalMixin",
"AreaEffectCloudMixin",
"ArrowMixin",
"BlockMixin",
"ChickenMixin",
"CowMixin",
"FlowingFluidMixin",
"ItemEntityMixin",
"LivingEntityMixin",
"MobEffectInstanceMixin",
"NodeEvaluatorMixin",
"PhantomMixin",
"PigMixin",
"PlayerMixin",
"ServerGamePacketListenerImplMixin",
"ServerLevelMixin",
"SheepMixin",
"SignBlockEntityMixin",
"ThrownPotionMixin",
"UnbreakingEnchantmentMixin",
"VillagerMakeLoveMixin",
"VillagerMixin",
"WallBlockMixin",
"accessor.AgeableMobAccessor",
"accessor.ArmorStandAccessor",
"accessor.BiomeAccessor",
"accessor.CreeperAccessor",
"accessor.DamageSourceAccessor",
"accessor.EntityAccessor",
"accessor.IntegerPropertyAccessor",
"accessor.LivingEntityAccessor",
"accessor.MobEffectInstanceAccessor",
"accessor.MobEntityAccessor",
"accessor.ServerLevelAccessor",
"accessor.SheepAccessor",
"accessor.SlimeAccessor",
"accessor.SuspiciousStewItemAccessor",
"accessor.SwordItemMixinAccessor",
"accessor.TadpoleAccessor",
"accessor.TextureSlotAccessor",
"accessor.ZombieVillagerMixinAccessor"
],
"client": [
"accessor.RecipeCollectionAccessor", "client.AbstractSignEditScreenMixin", "client.AnvilScreenMixin", "client.ClientPackListenerMixin",
Expand Down

0 comments on commit aba3a91

Please sign in to comment.