Skip to content

Commit

Permalink
custom potions recipe thingies
Browse files Browse the repository at this point in the history
  • Loading branch information
andi-makes committed Jun 16, 2024
1 parent 1438b7a commit 5f96e66
Show file tree
Hide file tree
Showing 16 changed files with 325 additions and 50 deletions.
15 changes: 0 additions & 15 deletions src/client/java/dev/schmarrn/mixin/client/ExampleClientMixin.java

This file was deleted.

4 changes: 1 addition & 3 deletions src/client/resources/beeg-smol.client.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
"required": true,
"package": "dev.schmarrn.mixin.client",
"compatibilityLevel": "JAVA_21",
"client": [
"ExampleClientMixin"
],
"client": [ ],
"injectors": {
"defaultRequire": 1
}
Expand Down
20 changes: 12 additions & 8 deletions src/main/java/dev/schmarrn/BeegSmol.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
package dev.schmarrn;

import dev.schmarrn.components.MyComponents;
import dev.schmarrn.items.MyItems;
import net.fabricmc.api.ModInitializer;
import net.minecraft.resources.ResourceLocation;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class BeegSmol implements ModInitializer {
// This logger is used to write text to the console and the log file.
// It is considered best practice to use your mod id as the logger's name.
// That way, it's clear which mod wrote info, warnings, and errors.
public static final Logger LOGGER = LoggerFactory.getLogger("beeg-smol");
public static final String MOD_ID = "beeg-smol";
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);

public static ResourceLocation rl(String path) {
return ResourceLocation.fromNamespaceAndPath(MOD_ID, path);
}

@Override
public void onInitialize() {
// This code runs as soon as Minecraft is in a mod-load-ready state.
// However, some things (like resources) may still be uninitialized.
// Proceed with mild caution.
MyMobEffects.init();
MyComponents.init();

LOGGER.info("Hello Fabric world!");
MyItems.init();
}
}
10 changes: 10 additions & 0 deletions src/main/java/dev/schmarrn/MyMobEffect.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package dev.schmarrn;

import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectCategory;

public class MyMobEffect extends MobEffect {
protected MyMobEffect(MobEffectCategory mobEffectCategory, int i) {
super(mobEffectCategory, i);
}
}
28 changes: 28 additions & 0 deletions src/main/java/dev/schmarrn/MyMobEffects.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package dev.schmarrn;

import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectCategory;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.world.entity.ai.attributes.Attributes;

public class MyMobEffects {
public static final Holder<MobEffect> BEEG = Registry.registerForHolder(BuiltInRegistries.MOB_EFFECT, BeegSmol.rl("beeg"), new MyMobEffect(MobEffectCategory.NEUTRAL, 0xFF00FF).addAttributeModifier(Attributes.SCALE, BeegSmol.rl("effect.beeg"), 0.5, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL));
public static final Holder<MobEffect> SMOL = Registry.registerForHolder(BuiltInRegistries.MOB_EFFECT, BeegSmol.rl("smol"), new MyMobEffect(MobEffectCategory.NEUTRAL, 0xFF00FF).addAttributeModifier(Attributes.SCALE, BeegSmol.rl("effect.smol"), -0.5, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL));

public static MobEffectInstance getMobEffectInstance(Holder<MobEffect> effect, int amplifier) {
int duration = -1;
boolean ambient = false;
boolean visible = false;
boolean showIcon = false;

return new MobEffectInstance(effect, duration, amplifier, ambient, visible, showIcon);
}

public static void init() {
// no-op
}
}
62 changes: 62 additions & 0 deletions src/main/java/dev/schmarrn/brewing/CustomBrewingRecipes.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package dev.schmarrn.brewing;

import dev.schmarrn.MyMobEffects;
import dev.schmarrn.items.Vial;
import net.minecraft.core.Holder;
import net.minecraft.core.component.DataComponents;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.alchemy.Potion;
import net.minecraft.world.item.alchemy.PotionContents;
import net.minecraft.world.item.alchemy.Potions;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class CustomBrewingRecipes {
public static final List<IBrewingRecipe> RECIPES = new ArrayList<>();

static {
register(new IBrewingRecipe() {
@Override
public boolean isBase(ItemStack base) {
Optional<Holder<Potion>> basePotion = base.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY).potion();
return basePotion.filter(Potions.THICK::is).isPresent();
}

@Override
public boolean isIngredient(ItemStack itemStack) {
return itemStack.is(Items.RED_MUSHROOM);
}

@Override
public ItemStack getOutput(ItemStack base, ItemStack ingredient) {
return Vial.getWithEffect(MyMobEffects.getMobEffectInstance(MyMobEffects.BEEG, 0));
}
});
}

public static boolean isIngredient(ItemStack stack) {
for (IBrewingRecipe recipe : RECIPES) {
if (recipe.isIngredient(stack)) {
return true;
}
}
return false;
}

public static boolean isBasis(ItemStack stack) {
for (IBrewingRecipe recipe : RECIPES) {
if (recipe.isBase(stack)) {
return true;
}
}

return false;
}

private static void register(IBrewingRecipe recipe) {
RECIPES.add(recipe);
}
}
12 changes: 12 additions & 0 deletions src/main/java/dev/schmarrn/brewing/IBrewingRecipe.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package dev.schmarrn.brewing;

import net.minecraft.world.item.ItemStack;

/**
* Inspired by neoforge: https://github.com/neoforged/NeoForge/blob/f923568cc0595b90034739ecc96af367ecacbdd5/src/main/java/net/neoforged/neoforge/common/brewing/IBrewingRecipe.java
*/
public interface IBrewingRecipe {
boolean isBase(ItemStack itemStack);
boolean isIngredient(ItemStack itemStack);
ItemStack getOutput(ItemStack base, ItemStack ingredient);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package dev.schmarrn.components;

import com.mojang.serialization.Codec;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.world.effect.MobEffectInstance;

import java.util.List;

public record MobEffectInstancesComponent(List<MobEffectInstance> effectInstances) {
public static final MobEffectInstancesComponent EMPTY = new MobEffectInstancesComponent(List.of());
public static final Codec<MobEffectInstancesComponent> CODEC = MobEffectInstance.CODEC.listOf().xmap(MobEffectInstancesComponent::new, MobEffectInstancesComponent::effectInstances);
public static final StreamCodec<RegistryFriendlyByteBuf, MobEffectInstancesComponent> STREAM_CODEC = MobEffectInstance.STREAM_CODEC.apply(ByteBufCodecs.list()).map(MobEffectInstancesComponent::new, MobEffectInstancesComponent::effectInstances);
}
21 changes: 21 additions & 0 deletions src/main/java/dev/schmarrn/components/MyComponents.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package dev.schmarrn.components;

import dev.schmarrn.BeegSmol;
import net.minecraft.core.Registry;
import net.minecraft.core.component.DataComponentType;
import net.minecraft.core.registries.BuiltInRegistries;

import java.util.function.UnaryOperator;

public class MyComponents {
public static final DataComponentType<MobEffectInstancesComponent> MOB_EFFECTS = MyComponents.register(
"mobeffects", builder -> builder.persistent(MobEffectInstancesComponent.CODEC).networkSynchronized(MobEffectInstancesComponent.STREAM_CODEC).cacheEncoding());

private static <T> DataComponentType<T> register(String string, UnaryOperator<DataComponentType.Builder<T>> unaryOperator) {
return Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, BeegSmol.rl(string), ((DataComponentType.Builder)unaryOperator.apply(DataComponentType.builder())).build());
}

public static void init() {
// no-op
}
}
14 changes: 14 additions & 0 deletions src/main/java/dev/schmarrn/items/MyItems.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package dev.schmarrn.items;

import dev.schmarrn.BeegSmol;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.world.item.Item;

public class MyItems {
public static final Item POTION = Registry.register(BuiltInRegistries.ITEM, BeegSmol.rl("vial"), new Vial(new Item.Properties()));

public static void init() {
// no-op
}
}
87 changes: 87 additions & 0 deletions src/main/java/dev/schmarrn/items/Vial.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package dev.schmarrn.items;

import dev.schmarrn.components.MobEffectInstancesComponent;
import dev.schmarrn.components.MyComponents;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.stats.Stats;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.*;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.gameevent.GameEvent;
import org.jetbrains.annotations.NotNull;

import java.util.List;

public class Vial extends Item {

public Vial(Properties properties) {
super(properties);
}

@Override
public @NotNull ItemStack getDefaultInstance() {
ItemStack itemStack = super.getDefaultInstance();
itemStack.set(MyComponents.MOB_EFFECTS, MobEffectInstancesComponent.EMPTY);
return itemStack;
}

public static @NotNull ItemStack getWithEffect(MobEffectInstance me) {
return getWithEffects(List.of(me));
}

public static @NotNull ItemStack getWithEffects(List<MobEffectInstance> mes) {
ItemStack itemStack = MyItems.POTION.getDefaultInstance();
itemStack.set(MyComponents.MOB_EFFECTS, new MobEffectInstancesComponent(mes));
return itemStack;
}

@Override
public @NotNull ItemStack finishUsingItem(ItemStack itemStack, Level level, LivingEntity livingEntity) {
if (!level.isClientSide) {
MobEffectInstancesComponent mobEffectInstancesComponent = itemStack.getOrDefault(MyComponents.MOB_EFFECTS, MobEffectInstancesComponent.EMPTY);
for (MobEffectInstance entry : mobEffectInstancesComponent.effectInstances()) {
livingEntity.addEffect(entry);
}
}

Player player = livingEntity instanceof Player ? (Player)livingEntity : null;

if (player instanceof ServerPlayer) {
CriteriaTriggers.CONSUME_ITEM.trigger((ServerPlayer)player, itemStack);
}
if (player != null) {
player.awardStat(Stats.ITEM_USED.get(this));
itemStack.consume(1, player);
}
if (player == null || !player.hasInfiniteMaterials()) {
if (itemStack.isEmpty()) {
return new ItemStack(Items.GLASS_BOTTLE);
}
if (player != null) {
player.getInventory().add(new ItemStack(Items.GLASS_BOTTLE));
}
}
livingEntity.gameEvent(GameEvent.DRINK);
return itemStack;
}

@Override
public int getUseDuration(ItemStack itemStack, LivingEntity livingEntity) {
return 32;
}

@Override
public @NotNull UseAnim getUseAnimation(ItemStack itemStack) {
return UseAnim.DRINK;
}

@Override
public @NotNull InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand interactionHand) {
return ItemUtils.startUsingInstantly(level, player, interactionHand);
}
}
15 changes: 0 additions & 15 deletions src/main/java/dev/schmarrn/mixin/ExampleMixin.java

This file was deleted.

51 changes: 51 additions & 0 deletions src/main/java/dev/schmarrn/mixin/PotionBrewingMixin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package dev.schmarrn.mixin;

import dev.schmarrn.brewing.IBrewingRecipe;
import dev.schmarrn.brewing.CustomBrewingRecipes;
import net.minecraft.core.Holder;
import net.minecraft.core.component.DataComponents;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.alchemy.Potion;
import net.minecraft.world.item.alchemy.PotionBrewing;
import net.minecraft.world.item.alchemy.PotionContents;

import java.util.Optional;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

import com.llamalad7.mixinextras.injector.ModifyReturnValue;

@Mixin(PotionBrewing.class)
public class PotionBrewingMixin {
@ModifyReturnValue(
method = "isPotionIngredient",
at = @At("RETURN")
)
private boolean bs$isPotionIngredient(boolean original, ItemStack ingredient) {
return original || CustomBrewingRecipes.isIngredient(ingredient);
}

@ModifyReturnValue(
method = "hasPotionMix",
at = @At("RETURN")
)
private boolean bs$hasPotionMix(boolean original, ItemStack base, ItemStack ingredient) {
return original || CustomBrewingRecipes.isBasis(base) && CustomBrewingRecipes.isIngredient(ingredient);
}

@ModifyReturnValue(
method = "mix",
at = @At("RETURN")
)
private ItemStack bs$mix(ItemStack original, ItemStack ingredient, ItemStack base) {
// TODO: Better Mixin Location
for (IBrewingRecipe recipe : CustomBrewingRecipes.RECIPES) {
if (recipe.isBase(base) && recipe.isIngredient(ingredient)) {
return recipe.getOutput(base, ingredient);
}
}

return original;
}
}
7 changes: 7 additions & 0 deletions src/main/resources/assets/beeg-smol/models/item/vial.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"parent": "item/generated",
"textures": {
"layer0": "item/potion_overlay",
"layer1": "item/potion"
}
}
Loading

0 comments on commit 5f96e66

Please sign in to comment.