From aba3a91c87d4b550e15ad28661c59e7c5614d9ff Mon Sep 17 00:00:00 2001 From: kd8lvt Date: Fri, 11 Oct 2024 13:34:43 -0400 Subject: [PATCH] feat: add bulk Digestion of items in Gastric Acid --- .../particles/ModParticleSpriteProvider.java | 1 + .../datagen/tags/ModItemTagsProvider.java | 5 + .../biomancy/particles/acid_bubble.json | 5 + .../items/cannot_be_digested_in_acid.json | 7 ++ .../client/particle/ParticleProviders.java | 14 +++ .../client/particle/VanillaDripParticle.java | 37 +++++++ .../biomancy/init/AcidInteractions.java | 91 ++++++++++++++++++ .../biomancy/init/ModParticleTypes.java | 1 + .../init/client/ClientSetupHandler.java | 1 + .../biomancy/init/tags/ModItemTags.java | 2 + .../biomancy/mixin/ItemEntityMixin.java | 18 ++++ .../textures/particle/acid_bubble.png | Bin 0 -> 147 bytes src/main/resources/mixins.biomancy.json | 48 +++++++-- 13 files changed, 223 insertions(+), 7 deletions(-) create mode 100644 src/generated/resources/assets/biomancy/particles/acid_bubble.json create mode 100644 src/generated/resources/data/biomancy/tags/items/cannot_be_digested_in_acid.json create mode 100644 src/main/java/com/github/elenterius/biomancy/mixin/ItemEntityMixin.java create mode 100644 src/main/resources/assets/biomancy/textures/particle/acid_bubble.png diff --git a/src/datagen/java/com/github/elenterius/biomancy/datagen/particles/ModParticleSpriteProvider.java b/src/datagen/java/com/github/elenterius/biomancy/datagen/particles/ModParticleSpriteProvider.java index 002be4c5f..d3fe91567 100644 --- a/src/datagen/java/com/github/elenterius/biomancy/datagen/particles/ModParticleSpriteProvider.java +++ b/src/datagen/java/com/github/elenterius/biomancy/datagen/particles/ModParticleSpriteProvider.java @@ -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"); } } diff --git a/src/datagen/java/com/github/elenterius/biomancy/datagen/tags/ModItemTagsProvider.java b/src/datagen/java/com/github/elenterius/biomancy/datagen/tags/ModItemTagsProvider.java index 0967b01c9..5a7c4e10d 100644 --- a/src/datagen/java/com/github/elenterius/biomancy/datagen/tags/ModItemTagsProvider.java +++ b/src/datagen/java/com/github/elenterius/biomancy/datagen/tags/ModItemTagsProvider.java @@ -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() { diff --git a/src/generated/resources/assets/biomancy/particles/acid_bubble.json b/src/generated/resources/assets/biomancy/particles/acid_bubble.json new file mode 100644 index 000000000..ba68a0297 --- /dev/null +++ b/src/generated/resources/assets/biomancy/particles/acid_bubble.json @@ -0,0 +1,5 @@ +{ + "textures": [ + "biomancy:acid_bubble" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/biomancy/tags/items/cannot_be_digested_in_acid.json b/src/generated/resources/data/biomancy/tags/items/cannot_be_digested_in_acid.json new file mode 100644 index 000000000..6ca09093e --- /dev/null +++ b/src/generated/resources/data/biomancy/tags/items/cannot_be_digested_in_acid.json @@ -0,0 +1,7 @@ +{ + "values": [ + "biomancy:nutrient_paste", + "biomancy:nutrient_bar", + "biomancy:living_flesh" + ] +} \ No newline at end of file diff --git a/src/main/java/com/github/elenterius/biomancy/client/particle/ParticleProviders.java b/src/main/java/com/github/elenterius/biomancy/client/particle/ParticleProviders.java index 164b28571..14c462545 100644 --- a/src/main/java/com/github/elenterius/biomancy/client/particle/ParticleProviders.java +++ b/src/main/java/com/github/elenterius/biomancy/client/particle/ParticleProviders.java @@ -64,4 +64,18 @@ public Particle createParticle(SimpleParticleType type, ClientLevel level, doubl } } + @OnlyIn(Dist.CLIENT) + public static class AcidBubbleProvider implements ParticleProvider { + 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; + } + } } diff --git a/src/main/java/com/github/elenterius/biomancy/client/particle/VanillaDripParticle.java b/src/main/java/com/github/elenterius/biomancy/client/particle/VanillaDripParticle.java index cc330d292..d2ed45b5a 100644 --- a/src/main/java/com/github/elenterius/biomancy/client/particle/VanillaDripParticle.java +++ b/src/main/java/com/github/elenterius/biomancy/client/particle/VanillaDripParticle.java @@ -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; @@ -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; + } + } + } diff --git a/src/main/java/com/github/elenterius/biomancy/init/AcidInteractions.java b/src/main/java/com/github/elenterius/biomancy/init/AcidInteractions.java index 852372496..3178f98e2 100644 --- a/src/main/java/com/github/elenterius/biomancy/init/AcidInteractions.java +++ b/src/main/java/com/github/elenterius/biomancy/init/AcidInteractions.java @@ -1,9 +1,17 @@ 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; @@ -11,6 +19,7 @@ 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; @@ -29,6 +38,7 @@ import java.util.Map; import java.util.Objects; +import java.util.Optional; public final class AcidInteractions { @@ -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 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 getDigestionRecipe(ItemEntity itemEntity, ItemStack stack, CompoundTag digestionData) { + Optional 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. + } + } } diff --git a/src/main/java/com/github/elenterius/biomancy/init/ModParticleTypes.java b/src/main/java/com/github/elenterius/biomancy/init/ModParticleTypes.java index 33af249c2..e673047f4 100644 --- a/src/main/java/com/github/elenterius/biomancy/init/ModParticleTypes.java +++ b/src/main/java/com/github/elenterius/biomancy/init/ModParticleTypes.java @@ -21,6 +21,7 @@ public final class ModParticleTypes { public static final RegistryObject LIGHT_GREEN_GLOW = register("light_green_glow", false); public static final RegistryObject HOSTILE = register("hostile", false); public static final RegistryObject BIOHAZARD = register("biohazard", false); + public static final RegistryObject ACID_BUBBLE = register("acid_bubble", false); private ModParticleTypes() {} diff --git a/src/main/java/com/github/elenterius/biomancy/init/client/ClientSetupHandler.java b/src/main/java/com/github/elenterius/biomancy/init/client/ClientSetupHandler.java index 5afebb12e..a8dea9893 100644 --- a/src/main/java/com/github/elenterius/biomancy/init/client/ClientSetupHandler.java +++ b/src/main/java/com/github/elenterius/biomancy/init/client/ClientSetupHandler.java @@ -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 diff --git a/src/main/java/com/github/elenterius/biomancy/init/tags/ModItemTags.java b/src/main/java/com/github/elenterius/biomancy/init/tags/ModItemTags.java index 9afd06e5d..0a1be5cd5 100644 --- a/src/main/java/com/github/elenterius/biomancy/init/tags/ModItemTags.java +++ b/src/main/java/com/github/elenterius/biomancy/init/tags/ModItemTags.java @@ -19,6 +19,8 @@ public final class ModItemTags { public static final TagKey SUGARS = tag("sugars"); + public static final TagKey CANNOT_BE_DIGESTED_IN_ACID = tag("cannot_be_digested_in_acid"); + private ModItemTags() {} private static TagKey tag(String name) { diff --git a/src/main/java/com/github/elenterius/biomancy/mixin/ItemEntityMixin.java b/src/main/java/com/github/elenterius/biomancy/mixin/ItemEntityMixin.java new file mode 100644 index 000000000..b7437583d --- /dev/null +++ b/src/main/java/com/github/elenterius/biomancy/mixin/ItemEntityMixin.java @@ -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); + } +} \ No newline at end of file diff --git a/src/main/resources/assets/biomancy/textures/particle/acid_bubble.png b/src/main/resources/assets/biomancy/textures/particle/acid_bubble.png new file mode 100644 index 0000000000000000000000000000000000000000..cdd12ea88d2f267b0a281a5d72b55ab52383c484 GIT binary patch literal 147 zcmeAS@N?(olHy`uVBq!ia0vp^93afW3?x5a^xFxf7>k44ofy`glX(f`@C5jTxB}@< z|NqbUKSS}q;+)T?{eXOyk|4iehX4QnZ`O6_0P%Fr7JbMnI}hQc_Z4 p#sMBSjb_F}44Y>t*r+M+GO)=p=-vrid=IFB!PC{xWt~$(699)9D? literal 0 HcmV?d00001 diff --git a/src/main/resources/mixins.biomancy.json b/src/main/resources/mixins.biomancy.json index 88494883a..0703d6971 100644 --- a/src/main/resources/mixins.biomancy.json +++ b/src/main/resources/mixins.biomancy.json @@ -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",