Fix crash due to transient components not being initialised

This commit is contained in:
Sollace 2024-10-03 19:56:43 +01:00
parent 214acef12c
commit 7de1675a82
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
2 changed files with 30 additions and 30 deletions

View file

@ -21,7 +21,7 @@ import net.minecraft.util.Util;
public class TransientComponentMap { public class TransientComponentMap {
private static final BiFunction<ItemStack, ?, ?> DEFAULT = (stack, t) -> t; private static final BiFunction<ItemStack, ?, ?> DEFAULT = (stack, t) -> t;
public static final TransientComponentMap INITIAL = Util.make(new TransientComponentMap(), map -> { public static final TransientComponentMap INITIAL = Util.make(new TransientComponentMap(null), map -> {
map.set(UDataComponentTypes.DIET_PROFILE, (s, original) -> { map.set(UDataComponentTypes.DIET_PROFILE, (s, original) -> {
if (original != null) { if (original != null) {
return original; return original;
@ -56,11 +56,18 @@ public class TransientComponentMap {
}); });
}); });
private final Map<ComponentType<?>, BiFunction<ItemStack, ?, ?>> components = new HashMap<>(); @Nullable
private final TransientComponentMap parent;
private Map<ComponentType<?>, BiFunction<ItemStack, ?, ?>> components;
private Optional<Entity> carrier = Optional.empty(); private Optional<Entity> carrier = Optional.empty();
private TransientComponentMap() {} private TransientComponentMap(TransientComponentMap parent) {
this.parent = parent;
if (parent == null) {
components = new HashMap<>();
}
}
public Optional<Entity> getCarrier() { public Optional<Entity> getCarrier() {
return carrier; return carrier;
@ -71,18 +78,25 @@ public class TransientComponentMap {
} }
public <T> void set(ComponentType<? extends T> type, BiFunction<ItemStack, T, T> getter) { public <T> void set(ComponentType<? extends T> type, BiFunction<ItemStack, T, T> getter) {
if (components == null) {
components = parent == null ? new HashMap<>() : new HashMap<>(parent.components);
}
components.put(type, getter); components.put(type, getter);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> T get(ComponentType<? extends T> type, ItemStack stack, T upstreamValue) { public <T> T get(ComponentType<? extends T> type, ItemStack stack, T upstreamValue) {
return ((BiFunction<ItemStack, T, T>)components.getOrDefault(type, DEFAULT)).apply(stack, upstreamValue); if (components != null) {
return ((BiFunction<ItemStack, T, T>)components.getOrDefault(type, DEFAULT)).apply(stack, upstreamValue);
}
if (parent != null) {
return parent.get(type, stack, upstreamValue);
}
return upstreamValue;
} }
public TransientComponentMap createCopy() { public TransientComponentMap createCopy() {
TransientComponentMap copy = new TransientComponentMap(); return new TransientComponentMap(this);
copy.components.putAll(components);
return copy;
} }
public interface Holder { public interface Holder {

View file

@ -1,16 +1,16 @@
package com.minelittlepony.unicopia.mixin; package com.minelittlepony.unicopia.mixin;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Supplier;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.google.common.base.Suppliers;
import com.minelittlepony.unicopia.entity.effect.FoodPoisoningStatusEffect; import com.minelittlepony.unicopia.entity.effect.FoodPoisoningStatusEffect;
import com.minelittlepony.unicopia.item.DamageChecker; import com.minelittlepony.unicopia.item.DamageChecker;
import com.minelittlepony.unicopia.item.ItemStackDuck; import com.minelittlepony.unicopia.item.ItemStackDuck;
@ -23,7 +23,6 @@ import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.tooltip.TooltipAppender;
import net.minecraft.item.tooltip.TooltipType; import net.minecraft.item.tooltip.TooltipType;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
@ -33,21 +32,16 @@ import net.minecraft.world.World;
@Mixin(ItemStack.class) @Mixin(ItemStack.class)
abstract class MixinItemStack implements ItemStackDuck { abstract class MixinItemStack implements ItemStackDuck {
private final TransientComponentMap transientComponents = TransientComponentMap.INITIAL.createCopy(); private final Supplier<TransientComponentMap> transientComponents = Suppliers.memoize(() -> TransientComponentMap.INITIAL.createCopy());
@Shadow
abstract <T extends TooltipAppender> void appendTooltip(
ComponentType<T> componentType, Item.TooltipContext context, Consumer<Text> textConsumer, TooltipType type
);
@Override @Override
public TransientComponentMap getTransientComponents() { public TransientComponentMap getTransientComponents() {
return transientComponents; return transientComponents.get();
} }
@Inject(method = "use", at = @At("HEAD"), cancellable = true) @Inject(method = "use", at = @At("HEAD"), cancellable = true)
private void onUse(World world, PlayerEntity user, Hand hand, CallbackInfoReturnable<TypedActionResult<ItemStack>> info) { private void onUse(World world, PlayerEntity user, Hand hand, CallbackInfoReturnable<TypedActionResult<ItemStack>> info) {
transientComponents.setCarrier(user); getTransientComponents().setCarrier(user);
TypedActionResult<ItemStack> result = FoodPoisoningStatusEffect.apply((ItemStack)(Object)this, user); TypedActionResult<ItemStack> result = FoodPoisoningStatusEffect.apply((ItemStack)(Object)this, user);
if (result.getResult() != ActionResult.PASS) { if (result.getResult() != ActionResult.PASS) {
info.setReturnValue(result); info.setReturnValue(result);
@ -56,30 +50,22 @@ abstract class MixinItemStack implements ItemStackDuck {
@Inject(method = "onStoppedUsing", at = @At("RETURN")) @Inject(method = "onStoppedUsing", at = @At("RETURN"))
public void onOnStoppedUsing(World world, LivingEntity user, int remainingUseTicks, CallbackInfo info) { public void onOnStoppedUsing(World world, LivingEntity user, int remainingUseTicks, CallbackInfo info) {
transientComponents.setCarrier(null); getTransientComponents().setCarrier(null);
} }
@Inject(method = "finishUsing", at = @At("RETURN")) @Inject(method = "finishUsing", at = @At("RETURN"))
private void afterFinishUsing(World world, LivingEntity user, CallbackInfoReturnable<ItemStack> info) { private void afterFinishUsing(World world, LivingEntity user, CallbackInfoReturnable<ItemStack> info) {
transientComponents.setCarrier(null); getTransientComponents().setCarrier(null);
} }
@Inject(method = "getTooltip", at = @At("HEAD")) @Inject(method = "getTooltip", at = @At("HEAD"))
public void beforeGetTooltip(Item.TooltipContext context, @Nullable PlayerEntity player, TooltipType type, CallbackInfoReturnable<List<Text>> info) { public void beforeGetTooltip(Item.TooltipContext context, @Nullable PlayerEntity player, TooltipType type, CallbackInfoReturnable<List<Text>> info) {
transientComponents.setCarrier(player); getTransientComponents().setCarrier(player);
} }
@Inject(method = "getTooltip", at = @At("RETURN")) @Inject(method = "getTooltip", at = @At("RETURN"))
public void afterGetTooltip(Item.TooltipContext context, @Nullable PlayerEntity player, TooltipType type, CallbackInfoReturnable<List<Text>> info) { public void afterGetTooltip(Item.TooltipContext context, @Nullable PlayerEntity player, TooltipType type, CallbackInfoReturnable<List<Text>> info) {
transientComponents.setCarrier(null); getTransientComponents().setCarrier(null);
}
@Inject(method = "getTooltip",
at = @At(value = "INVOKE",
target = "net/minecraft/item/ItemStack.appendAttributeModifiersTooltip(Ljava/util/function/Consumer;Lnet/minecraft/entity/player/PlayerEntity;)V"
))
public void onGetTooltip(Item.TooltipContext context, @Nullable PlayerEntity player, TooltipType type, CallbackInfoReturnable<List<Text>> info) {
} }
@Inject(method = "takesDamageFrom", at = @At("HEAD")) @Inject(method = "takesDamageFrom", at = @At("HEAD"))