diff --git a/patches/minecraft/net/minecraft/client/multiplayer/ClientPacketListener.java.patch b/patches/minecraft/net/minecraft/client/multiplayer/ClientPacketListener.java.patch index dd9af031f1..adfb1c159f 100644 --- a/patches/minecraft/net/minecraft/client/multiplayer/ClientPacketListener.java.patch +++ b/patches/minecraft/net/minecraft/client/multiplayer/ClientPacketListener.java.patch @@ -66,15 +66,6 @@ } public void m_7244_(ClientboundPlayerLookAtPacket p_105054_) { -@@ -1245,7 +_,7 @@ - PacketUtils.m_131363_(p_105130_, this, this.f_104888_); - Entity entity = this.f_104889_.m_6815_(p_105130_.m_133622_()); - if (entity instanceof LivingEntity) { -- MobEffect mobeffect = MobEffect.m_19453_(p_105130_.m_211135_()); -+ MobEffect mobeffect = MobEffect.m_19453_(p_105130_.m_211135_() & 0xFF); - if (mobeffect != null) { - MobEffectInstance mobeffectinstance = new MobEffectInstance(mobeffect, p_105130_.m_133625_(), p_105130_.m_133624_(), p_105130_.m_133627_(), p_105130_.m_133626_(), p_105130_.m_133628_()); - mobeffectinstance.m_19562_(p_105130_.m_133619_()); @@ -1262,6 +_,7 @@ } diff --git a/patches/minecraft/net/minecraft/world/effect/MobEffectInstance.java.patch b/patches/minecraft/net/minecraft/world/effect/MobEffectInstance.java.patch index 8f9c5ba6ae..8ddba77155 100644 --- a/patches/minecraft/net/minecraft/world/effect/MobEffectInstance.java.patch +++ b/patches/minecraft/net/minecraft/world/effect/MobEffectInstance.java.patch @@ -26,7 +26,15 @@ } public int m_19557_() { -@@ -221,12 +_,13 @@ +@@ -206,6 +_,7 @@ + + public CompoundTag m_19555_(CompoundTag p_19556_) { + p_19556_.m_128344_("Id", (byte)MobEffect.m_19459_(this.m_19544_())); ++ net.minecraftforge.common.ForgeHooks.saveMobEffect(p_19556_, "forge:id", this.m_19544_()); + this.m_19567_(p_19556_); + return p_19556_; + } +@@ -221,13 +_,15 @@ this.f_19510_.m_19555_(compoundtag); p_19568_.m_128365_("HiddenEffect", compoundtag); } @@ -39,8 +47,10 @@ - int i = p_19561_.m_128445_("Id"); + int i = p_19561_.m_128445_("Id") & 0xFF; MobEffect mobeffect = MobEffect.m_19453_(i); ++ mobeffect = net.minecraftforge.common.ForgeHooks.loadMobEffect(p_19561_, "forge:id", mobeffect); return mobeffect == null ? null : m_19545_(mobeffect, p_19561_); } + @@ -250,7 +_,7 @@ mobeffectinstance = m_19545_(p_19546_, p_19547_.m_128469_("HiddenEffect")); } diff --git a/patches/minecraft/net/minecraft/world/entity/animal/MushroomCow.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/MushroomCow.java.patch index 9581a8ef6c..7412116082 100644 --- a/patches/minecraft/net/minecraft/world/entity/animal/MushroomCow.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/animal/MushroomCow.java.patch @@ -51,6 +51,22 @@ } +@@ -182,6 +_,7 @@ + p_28944_.m_128359_("Type", this.m_28955_().f_28960_); + if (this.f_28909_ != null) { + p_28944_.m_128344_("EffectId", (byte)MobEffect.m_19459_(this.f_28909_)); ++ net.minecraftforge.common.ForgeHooks.saveMobEffect(p_28944_, "forge:effect_id", this.f_28909_); + p_28944_.m_128405_("EffectDuration", this.f_28910_); + } + +@@ -192,6 +_,7 @@ + this.m_28928_(MushroomCow.MushroomType.m_28976_(p_28936_.m_128461_("Type"))); + if (p_28936_.m_128425_("EffectId", 1)) { + this.f_28909_ = MobEffect.m_19453_(p_28936_.m_128445_("EffectId")); ++ this.f_28909_ = net.minecraftforge.common.ForgeHooks.loadMobEffect(p_28936_, "forge:effect_id", this.f_28909_); + } + + if (p_28936_.m_128425_("EffectDuration", 3)) { @@ -238,6 +_,11 @@ } diff --git a/patches/minecraft/net/minecraft/world/item/SuspiciousStewItem.java.patch b/patches/minecraft/net/minecraft/world/item/SuspiciousStewItem.java.patch new file mode 100644 index 0000000000..5f7fed76c1 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/item/SuspiciousStewItem.java.patch @@ -0,0 +1,18 @@ +--- a/net/minecraft/world/item/SuspiciousStewItem.java ++++ b/net/minecraft/world/item/SuspiciousStewItem.java +@@ -22,6 +_,7 @@ + ListTag listtag = compoundtag.m_128437_("Effects", 9); + CompoundTag compoundtag1 = new CompoundTag(); + compoundtag1.m_128344_("EffectId", (byte)MobEffect.m_19459_(p_43260_)); ++ net.minecraftforge.common.ForgeHooks.saveMobEffect(compoundtag1, "forge:effect_id", p_43260_); + compoundtag1.m_128405_("EffectDuration", p_43261_); + listtag.add(compoundtag1); + compoundtag.m_128365_("Effects", listtag); +@@ -41,6 +_,7 @@ + } + + MobEffect mobeffect = MobEffect.m_19453_(compoundtag1.m_128445_("EffectId")); ++ mobeffect = net.minecraftforge.common.ForgeHooks.loadMobEffect(compoundtag1, "forge:effect_id", mobeffect); + if (mobeffect != null) { + p_43265_.m_7292_(new MobEffectInstance(mobeffect, j)); + } diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index fe03ceddf8..c42ebbb665 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -25,6 +25,7 @@ import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; +import com.google.common.base.Strings; import com.google.common.base.Suppliers; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; @@ -45,10 +46,12 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import it.unimi.dsi.fastutil.longs.LongSet; +import net.minecraft.ResourceLocationException; import net.minecraft.advancements.Advancement; import net.minecraft.core.*; import net.minecraft.tags.BlockTags; import net.minecraft.tags.TagKey; +import net.minecraft.world.effect.MobEffect; import net.minecraft.world.entity.ai.attributes.Attribute; import net.minecraft.world.entity.ai.attributes.AttributeModifier; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; @@ -1401,4 +1404,32 @@ public class ForgeHooks LOGGER.error(WORLDPERSISTENCE, buf.toString()); } } + + public static void saveMobEffect(CompoundTag nbt, String key, MobEffect effect) + { + var registryName = effect.getRegistryName(); + if (registryName != null) + { + nbt.putString(key, registryName.toString()); + } + } + + @Nullable + public static MobEffect loadMobEffect(CompoundTag nbt, String key, @Nullable MobEffect fallback) + { + var registryName = nbt.getString(key); + if (Strings.isNullOrEmpty(registryName)) + { + return fallback; + } + try + { + return ForgeRegistries.MOB_EFFECTS.getValue(new ResourceLocation(registryName)); + } + catch (ResourceLocationException e) + { + return fallback; + } + } + } diff --git a/src/test/java/net/minecraftforge/debug/ManyMobEffectsTest.java b/src/test/java/net/minecraftforge/debug/ManyMobEffectsTest.java new file mode 100644 index 0000000000..92d9e7650e --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/ManyMobEffectsTest.java @@ -0,0 +1,140 @@ +/* + * Minecraft Forge - Forge Development LLC + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.debug; + +import net.minecraft.Util; +import net.minecraft.core.NonNullList; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.world.effect.MobEffect; +import net.minecraft.world.effect.MobEffectCategory; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.animal.MushroomCow; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.SuspiciousStewItem; +import net.minecraft.world.item.alchemy.PotionUtils; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.fml.util.ObfuscationReflectionHelper; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegistryObject; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; + +/** + * Registers 255 mob effects that log every tick on the client. + * Used to test the patches for saving MobEffects to NBT. + * + * To verify correct function: + * - Check that the Potion item and suspicious stew item provided via the creative tab function correctly + * - Check that the effect given by the above items can persist on an entity as well as on ItemStacks in inventories + * - Right click a Mushroom Cow using the above given Potion Item. Verify that it obtained the effect by right-clicking + * it again using an empty hand before and after reloading the world. + */ +@Mod(ManyMobEffectsTest.MODID) +public class ManyMobEffectsTest +{ + + static final String MODID = "many_mob_effects_test"; + + private static final boolean ENABLED = true; + + private static final Logger LOGGER = LogManager.getLogger(); + + private static final CreativeModeTab CREATIVE_TAB = new CreativeModeTab(MODID) + { + @Override + public ItemStack makeIcon() + { + return new ItemStack(Items.POTION); + } + + @Override + public void fillItemList(NonNullList stacks) + { + super.fillItemList(stacks); + var stack = new ItemStack(Items.POTION); + PotionUtils.setCustomEffects(stack, List.of(new MobEffectInstance(LAST_EFFECT.get(), 1000))); + stacks.add(stack); + + stack = new ItemStack(Items.SUSPICIOUS_STEW); + SuspiciousStewItem.saveMobEffect(stack, LAST_EFFECT.get(), 1000); + stacks.add(stack); + } + }; + + private static final DeferredRegister MOB_EFFECTS = DeferredRegister.create(ForgeRegistries.MOB_EFFECTS, MODID); + private static final RegistryObject LAST_EFFECT; + + static + { + RegistryObject effect = null; + for (int i = 0; i < 255; i++) + { + final var index = i; + effect = MOB_EFFECTS.register("effect_" + i, () -> new MobEffect(MobEffectCategory.NEUTRAL, 0xFF0000) + { + @Override + public void applyEffectTick(LivingEntity entity, int amplifier) + { + if (entity.level.isClientSide) + { + LOGGER.info("Effect Tick for {} on the client", index); + } + } + + @Override + public boolean isDurationEffectTick(int duration, int amplifier) + { + return true; + } + }); + } + LAST_EFFECT = effect; + } + + public ManyMobEffectsTest() + { + if (!ENABLED) return; + IEventBus modBus = FMLJavaModLoadingContext.get().getModEventBus(); + MOB_EFFECTS.register(modBus); + MinecraftForge.EVENT_BUS.addListener(ManyMobEffectsTest::mobInteract); + } + + private static void mobInteract(PlayerInteractEvent.EntityInteract event) + { + if (!event.getTarget().getLevel().isClientSide() && event.getTarget() instanceof MushroomCow cow) + { + var heldItem = event.getPlayer().getItemInHand(event.getHand()); + if (heldItem.is(Items.POTION)) + { + var effects = PotionUtils.getMobEffects(heldItem); + if (!effects.isEmpty()) + { + ObfuscationReflectionHelper.setPrivateValue(MushroomCow.class, cow, effects.get(0).getEffect(), "f_289" + "09_"); + ObfuscationReflectionHelper.setPrivateValue(MushroomCow.class, cow, effects.get(0).getDuration(), "f_289" + "10_"); + } + } + else if (heldItem.isEmpty()) + { + var effect = ((MobEffect) ObfuscationReflectionHelper.getPrivateValue(MushroomCow.class, cow, "f_289" + "09_")); + if (effect != null) + { + event.getPlayer().sendMessage(new TextComponent(String.valueOf(effect.getRegistryName())), Util.NIL_UUID); + } + } + } + } + +} diff --git a/src/test/resources/META-INF/mods.toml b/src/test/resources/META-INF/mods.toml index 66e7de192f..545bdc63d9 100644 --- a/src/test/resources/META-INF/mods.toml +++ b/src/test/resources/META-INF/mods.toml @@ -200,6 +200,8 @@ license="LGPL v2.1" modId="hidden_tooltip_parts" [[mods]] modId="gametest_test" +[[mods]] + modId="many_mob_effects_test" [[mods]] modId="potion_size_event_test" [[mods]]