Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ default boolean removeStatusEffect(@NotNull Holder<StatusEffect> type, @NotNull
}

/**
* Removes all status effects.
* Removes the status effects that {@link StatusEffectRemovalReason#removesEffect(StatusEffectInstance)} returns {@code true} for.
*
* @param reason the reason to remove the status effects
* @return the number of status effects that were successfully removed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.effect.StatusEffect;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.item.ItemStack;
import net.minecraft.item.RemoveEffectsComponent;
import net.minecraft.util.Identifier;

import org.quiltmc.qsl.entity.effect.impl.QuiltStatusEffectInternals;
Expand Down Expand Up @@ -74,10 +76,14 @@ public class StatusEffectRemovalReason {
new StatusEffectRemovalReason(QuiltStatusEffectInternals.id("command.one"));

/**
* Used when effects are removed via drinking milk. Does <em>not</em> have to be the vanilla milk bucket.
* The identifier used when effects are removed via the {@link net.minecraft.item.ClearAllEffectsComponent}, such as a milk bucket.
*/
public static final StatusEffectRemovalReason DRANK_MILK =
new StatusEffectRemovalReason(QuiltStatusEffectInternals.id("action.drank_milk"));
public static final Identifier CLEAR_ALL_EFFECTS_COMPONENT_ID = QuiltStatusEffectInternals.id("action.consume.clear_all_effects");

/**
* The identifier used when effects are removed via the {@link net.minecraft.item.RemoveEffectsComponent}, such as poison with honey bottles.
*/
public static final Identifier REMOVE_EFFECTS_COMPONENT_ID = QuiltStatusEffectInternals.id("action.consume.remove_effects");

protected final @NotNull Identifier id;

Expand Down Expand Up @@ -110,4 +116,37 @@ public StatusEffectRemovalReason(@NotNull Identifier id) {
public boolean removesEffect(StatusEffectInstance effect) {
return true;
}

/**
* A removal reason that stems from a consumption action that has an associated {@link ItemStack}.
*/
public static class ConsumeRemovalReason extends StatusEffectRemovalReason {
private final ItemStack stack;

public ConsumeRemovalReason(@NotNull Identifier id, ItemStack stack) {
super(id);
this.stack = stack;
}

public ItemStack stack() {
return this.stack;
}
}

/**
* A specific removal for the {@link RemoveEffectsComponent}.
*/
public static class RemoveEffectsComponentReason extends ConsumeRemovalReason {
private final net.minecraft.item.RemoveEffectsComponent component;

public RemoveEffectsComponentReason(ItemStack stack, net.minecraft.item.RemoveEffectsComponent component) {
super(REMOVE_EFFECTS_COMPONENT_ID, stack);
this.component = component;
}

@Override
public boolean removesEffect(StatusEffectInstance effect) {
return this.component.effects().contains(effect.getEffectType());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,28 @@

package org.quiltmc.qsl.entity.effect.mixin;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
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.CallbackInfoReturnable;

import net.minecraft.item.ClearAllEffectsComponent;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.minecraft.entity.LivingEntity;

import org.quiltmc.qsl.entity.effect.api.StatusEffectRemovalReason;
import org.quiltmc.qsl.entity.effect.impl.QuiltStatusEffectInternals;

// See LivingEntityMixin
@Mixin(value = ClearAllEffectsComponent.class, priority = QuiltStatusEffectInternals.MIXIN_PRIORITY)
public abstract class ClearAllEffectsComponentMixin {
@Inject(method = "apply", at = @At(value = "HEAD"))
private void quilt$addRemovalReason(
World world, ItemStack stack, LivingEntity entity, CallbackInfoReturnable<Boolean> cir
@WrapOperation(method = "apply", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;clearStatusEffects()Z"))
private boolean quilt$addRemovalReason(
LivingEntity instance, Operation<Boolean> original, World world, ItemStack stack
) {
entity.clearStatusEffects(StatusEffectRemovalReason.DRANK_MILK);
return instance.clearStatusEffects(
new StatusEffectRemovalReason.ConsumeRemovalReason(StatusEffectRemovalReason.CLEAR_ALL_EFFECTS_COMPONENT_ID, stack)
) > 0;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2022 The Quilt Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.quiltmc.qsl.entity.effect.mixin;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.effect.StatusEffect;
import net.minecraft.item.ItemStack;
import net.minecraft.item.RemoveEffectsComponent;
import net.minecraft.registry.Holder;
import net.minecraft.world.World;

import org.quiltmc.qsl.entity.effect.api.StatusEffectRemovalReason;
import org.quiltmc.qsl.entity.effect.impl.QuiltStatusEffectInternals;

// See LivingEntityMixin
@Mixin(value = RemoveEffectsComponent.class, priority = QuiltStatusEffectInternals.MIXIN_PRIORITY)
public abstract class RemoveEffectsComponentMixin {
@WrapOperation(method = "apply", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;removeStatusEffect(Lnet/minecraft/registry/Holder;)Z"))
private boolean quilt$addRemovalReason(
LivingEntity instance, Holder<StatusEffect> effect, Operation<Boolean> original, World world, ItemStack stack
) {
return instance.removeStatusEffect(
effect, new StatusEffectRemovalReason.RemoveEffectsComponentReason(stack, ((RemoveEffectsComponent) (Object) this))
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"ClearAllEffectsComponentMixin",
"EffectCommandMixin",
"LivingEntityMixin",
"RemoveEffectsComponentMixin",
"StatusEffectAccessor",
"StatusEffectMixin"
],
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,31 @@

package org.quiltmc.qsl.entity.effect.test;

import com.mojang.serialization.MapCodec;

import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.ConsumableComponent;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffectType;
import net.minecraft.item.ConsumeEffect;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.item.UseAnimation;
import net.minecraft.network.RegistryByteBuf;
import net.minecraft.network.codec.PacketCodec;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.Identifier;
import net.minecraft.world.World;

import org.quiltmc.loader.api.ModContainer;
import org.quiltmc.qsl.base.api.entrypoint.ModInitializer;
import org.quiltmc.qsl.entity.effect.api.StatusEffectEvents;
import org.quiltmc.qsl.entity.effect.api.StatusEffectRemovalReason;

public final class StatusEffectTest implements ModInitializer {
Expand All @@ -37,22 +50,67 @@ public static Identifier createId(String path) {
return Identifier.of(NAMESPACE, path);
}

public static final StatusEffectRemovalReason DRANK_PASTEURIZED_MILK =
new StatusEffectRemovalReason(createId("action.drank_pasteurized_milk")) {
@Override
public boolean removesEffect(StatusEffectInstance effect) {
return effect.getEffectType().getValue().getType() == StatusEffectType.HARMFUL;
}
};
public static class DrankPasteurizedMilkRemovalReason extends StatusEffectRemovalReason.ConsumeRemovalReason {
public static final Identifier DRANK_PASTEURIZED_MILK_ID = createId("action.consume.drank_pasteurized_milk");
public DrankPasteurizedMilkRemovalReason(ItemStack stack) {
super(DRANK_PASTEURIZED_MILK_ID, stack);
}

@Override
public boolean removesEffect(StatusEffectInstance effect) {
return effect.getEffectType().getValue().getType() == StatusEffectType.HARMFUL;
}
}

public record DrankPasteurizedMilk() implements ConsumeEffect {
public static final ConsumeEffect.Type<DrankPasteurizedMilk> DRANK_PASTEURIZED_MILK = Registry.register(
Registries.CONSUME_EFFECT_TYPE,
createId("drank_pasteurized_milk"),
new ConsumeEffect.Type<>(DrankPasteurizedMilk.CODEC, DrankPasteurizedMilk.PACKET_CODEC)
);

public static final DrankPasteurizedMilk INSTANCE = new DrankPasteurizedMilk();
public static final MapCodec<DrankPasteurizedMilk> CODEC = MapCodec.unit(INSTANCE);
public static final PacketCodec<RegistryByteBuf, DrankPasteurizedMilk> PACKET_CODEC = PacketCodec.unit(INSTANCE);

@Override
public Type<? extends ConsumeEffect> getType() {
return DRANK_PASTEURIZED_MILK;
}

@Override
public boolean apply(World world, ItemStack stack, LivingEntity entity) {
return entity.clearStatusEffects(new DrankPasteurizedMilkRemovalReason(stack)) > 0;
}
}

@Override
public void onInitialize(ModContainer mod) {
RegistryKey<Item> bucketKey = RegistryKey.of(RegistryKeys.ITEM, createId("pasteurized_milk_bucket"));
Registry.register(Registries.ITEM, bucketKey, new PasteurizedMilkBucketItem(
Registry.register(Registries.ITEM, bucketKey, new Item(
new Item.Settings()
.key(bucketKey)
.recipeRemainder(Items.BUCKET)
.useRemainder(Items.BUCKET)
.maxCount(1)
.component(DataComponentTypes.CONSUMABLE,
ConsumableComponent.builder()
.consumeSeconds(1.6F)
.animation(UseAnimation.DRINK)
.sound(SoundEvents.ENTITY_GENERIC_DRINK)
.hasConsumeParticles(false)
.effect(DrankPasteurizedMilk.INSTANCE)
.build())
));

StatusEffectEvents.ON_REMOVED.register((entity, effect, reason) -> {
if (reason instanceof DrankPasteurizedMilkRemovalReason milk) {
System.out.println("Removed " + effect.getTranslationKey() + " with pasteurized milk{" + milk.stack().toString() + "}!");
} else if (reason instanceof StatusEffectRemovalReason.ConsumeRemovalReason consume) {
System.out.println("Removed " + effect.getTranslationKey() + " with consume reason " + consume.getId() + "{" + consume.stack().toString() + "}!");
} else {
System.out.println("Removed " + effect.getTranslationKey() + " with reason " + reason.getId());
}
});
}
}
Loading