diff --git a/testframework/src/main/java/net/neoforged/testframework/gametest/ExtendedGameTestHelper.java b/testframework/src/main/java/net/neoforged/testframework/gametest/ExtendedGameTestHelper.java index 61a02e0838..3aa8d6a16b 100644 --- a/testframework/src/main/java/net/neoforged/testframework/gametest/ExtendedGameTestHelper.java +++ b/testframework/src/main/java/net/neoforged/testframework/gametest/ExtendedGameTestHelper.java @@ -5,24 +5,30 @@ package net.neoforged.testframework.gametest; +import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.mojang.authlib.GameProfile; import io.netty.channel.embedded.EmbeddedChannel; import java.util.List; +import java.util.Set; import java.util.UUID; import java.util.function.BiPredicate; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Stream; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.gametest.framework.GameTestAssertException; import net.minecraft.gametest.framework.GameTestAssertPosException; import net.minecraft.gametest.framework.GameTestHelper; import net.minecraft.gametest.framework.GameTestInfo; +import net.minecraft.gametest.framework.GameTestListener; import net.minecraft.network.Connection; import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.protocol.PacketFlow; import net.minecraft.server.network.CommonListenerCookie; +import net.minecraft.world.Difficulty; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.effect.MobEffect; @@ -42,6 +48,9 @@ import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; +import net.neoforged.bus.api.Event; +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.event.entity.living.LivingKnockBackEvent; import org.jetbrains.annotations.Nullable; public class ExtendedGameTestHelper extends GameTestHelper { @@ -109,6 +118,7 @@ public void tick() { this.getLevel().getServer().getConnection().getConnections().add(connection); this.testInfo.addListener(serverplayer); serverplayer.gameMode.changeGameModeForPlayer(gameType); + serverplayer.setYRot(180); return serverplayer; } @@ -203,6 +213,78 @@ public void pulseRedstone(int x, int y, int z, long delay) { pulseRedstone(new BlockPos(x, y, z), delay); } + public void assertPlayerHasItem(Player player, Item item) { + assertTrue(player.getInventory().hasAnyOf(Set.of(item)), "Player doesn't have '" + BuiltInRegistries.ITEM.getKey(item) + "' in their inventory!"); + } + + public void requireDifficulty(final Difficulty difficulty) { + final var oldDifficulty = getLevel().getServer().getWorldData().getDifficulty(); + if (oldDifficulty != difficulty) { + getLevel().getServer().setDifficulty(difficulty, true); + addEndListener(passed -> getLevel().getServer().setDifficulty(oldDifficulty, true)); + } + } + + public void addEndListener(Consumer listener) { + testInfo.addListener(new GameTestListener() { + @Override + public void testStructureLoaded(GameTestInfo info) { + + } + + @Override + public void testPassed(GameTestInfo info) { + listener.accept(true); + } + + @Override + public void testFailed(GameTestInfo info) { + listener.accept(false); + } + }); + } + + public T catchException(final ThrowingSupplier supplier) { + try { + return supplier.get(); + } catch (Throwable throwable) { + throw new GameTestAssertException(throwable.getMessage()); + } + } + + public void catchException(final ThrowingRunnable run) { + try { + run.run(); + } catch (Throwable throwable) { + throw new GameTestAssertException(throwable.getMessage()); + } + } + + public T requireEntityAt(EntityType type, int x, int y, int z) { + return requireEntityAt(type, new BlockPos(x, y, z)); + } + + public T requireEntityAt(EntityType type, BlockPos pos) { + final var inRange = getEntities(type, pos, 2); + assertTrue(inRange.size() == 1, "Only one entity must be present at " + pos); + return inRange.get(0); + } + + @CanIgnoreReturnValue + public T knockbackResistant(T entity) { + addTemporaryListener((final LivingKnockBackEvent event) -> { + if (event.getEntity().getUUID().equals(entity.getUUID())) { + event.setCanceled(true); + } + }); + return entity; + } + + public void addTemporaryListener(Consumer event) { + NeoForge.EVENT_BUS.addListener(event); + addEndListener(success -> NeoForge.EVENT_BUS.unregister(event)); + } + public void assertMobEffectPresent(E entity, MobEffect effect, String testName) { assertEntityProperty(entity, e -> e.hasEffect(effect), testName); } @@ -210,4 +292,14 @@ public void assertMobEffectPresent(E entity, MobEffect public void assertMobEffectAbsent(E entity, MobEffect effect, String testName) { assertEntityProperty(entity, e -> !e.hasEffect(effect), testName); } + + @FunctionalInterface + public interface ThrowingSupplier { + T get() throws Throwable; + } + + @FunctionalInterface + public interface ThrowingRunnable { + void run() throws Throwable; + } } diff --git a/testframework/src/main/java/net/neoforged/testframework/gametest/ParametrizedGameTestSequence.java b/testframework/src/main/java/net/neoforged/testframework/gametest/ParametrizedGameTestSequence.java index b4325a80c7..8c45f9f677 100644 --- a/testframework/src/main/java/net/neoforged/testframework/gametest/ParametrizedGameTestSequence.java +++ b/testframework/src/main/java/net/neoforged/testframework/gametest/ParametrizedGameTestSequence.java @@ -11,6 +11,7 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; +import net.minecraft.gametest.framework.GameTestAssertException; import net.minecraft.gametest.framework.GameTestInfo; import net.minecraft.gametest.framework.GameTestSequence; @@ -25,7 +26,13 @@ public ParametrizedGameTestSequence(GameTestInfo info, ExtendedSequence sequence final AtomicReference val = new AtomicReference<>(); sequence.thenExecute(() -> val.set(value.get())); - this.value = val::get; + this.value = () -> { + final var v = val.get(); + if (v == null) { + throw new GameTestAssertException("Expected value to be non-null!"); + } + return v; + }; } public ParametrizedGameTestSequence thenWaitUntil(Runnable condition) { diff --git a/testframework/src/main/java/net/neoforged/testframework/impl/reg/RegistrationHelperImpl.java b/testframework/src/main/java/net/neoforged/testframework/impl/reg/RegistrationHelperImpl.java index 5197c57353..9ae23e022d 100644 --- a/testframework/src/main/java/net/neoforged/testframework/impl/reg/RegistrationHelperImpl.java +++ b/testframework/src/main/java/net/neoforged/testframework/impl/reg/RegistrationHelperImpl.java @@ -13,8 +13,10 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Supplier; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.data.CachedOutput; @@ -25,6 +27,7 @@ import net.minecraft.resources.ResourceLocation; import net.neoforged.bus.api.Event; import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.attachment.AttachmentType; import net.neoforged.neoforge.client.model.generators.BlockStateProvider; import net.neoforged.neoforge.client.model.generators.ItemModelProvider; import net.neoforged.neoforge.client.model.generators.ModelProvider; @@ -33,6 +36,7 @@ import net.neoforged.neoforge.common.data.LanguageProvider; import net.neoforged.neoforge.data.event.GatherDataEvent; import net.neoforged.neoforge.registries.DeferredRegister; +import net.neoforged.testframework.registration.DeferredAttachmentTypes; import net.neoforged.testframework.registration.DeferredBlocks; import net.neoforged.testframework.registration.DeferredEntityTypes; import net.neoforged.testframework.registration.DeferredItems; @@ -137,6 +141,13 @@ public DeferredEntityTypes entityTypes() { return entityTypes; } + private final DeferredRegistrar, DeferredAttachmentTypes> attachments = new DeferredRegistrar<>((namespace, reg) -> new DeferredAttachmentTypes(namespace)); + + @Override + public DeferredAttachmentTypes attachments() { + return attachments.get(); + } + @Override public String modId() { return modId; @@ -187,4 +198,24 @@ public String getName() { } })); } + + private final class DeferredRegistrar> implements Supplier { + private final BiFunction factory; + + private T cached; + + private DeferredRegistrar(BiFunction factory) { + this.factory = factory; + } + + @Override + public T get() { + if (cached == null) { + cached = factory.apply(RegistrationHelperImpl.this.modId, RegistrationHelperImpl.this); + registrars.put(cached.getRegistryKey(), cached); + if (RegistrationHelperImpl.this.bus != null) cached.register(bus); + } + return cached; + } + } } diff --git a/testframework/src/main/java/net/neoforged/testframework/registration/DeferredAttachmentTypes.java b/testframework/src/main/java/net/neoforged/testframework/registration/DeferredAttachmentTypes.java new file mode 100644 index 0000000000..e8a90867d3 --- /dev/null +++ b/testframework/src/main/java/net/neoforged/testframework/registration/DeferredAttachmentTypes.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.testframework.registration; + +import java.util.function.Supplier; +import java.util.function.UnaryOperator; +import net.neoforged.neoforge.attachment.AttachmentType; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.neoforged.neoforge.registries.NeoForgeRegistries; + +public class DeferredAttachmentTypes extends DeferredRegister> { + public DeferredAttachmentTypes(String namespace) { + super(NeoForgeRegistries.Keys.ATTACHMENT_TYPES, namespace); + } + + public AttachmentType registerSimpleAttachment(String name, Supplier defaultValue) { + return register(name, defaultValue, UnaryOperator.identity()); + } + + public AttachmentType register(String name, Supplier defaultValue, UnaryOperator> factory) { + final var attach = factory.apply(AttachmentType.builder(defaultValue)).build(); + register(name, () -> attach); + return attach; + } +} diff --git a/testframework/src/main/java/net/neoforged/testframework/registration/RegistrationHelper.java b/testframework/src/main/java/net/neoforged/testframework/registration/RegistrationHelper.java index b61db605ae..d2ae734c5f 100644 --- a/testframework/src/main/java/net/neoforged/testframework/registration/RegistrationHelper.java +++ b/testframework/src/main/java/net/neoforged/testframework/registration/RegistrationHelper.java @@ -40,6 +40,11 @@ public interface RegistrationHelper { */ DeferredEntityTypes entityTypes(); + /** + * {@return a helper for attachment type registration} + */ + DeferredAttachmentTypes attachments(); + /** * {@return the mod id of this helper} */ diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/client/ClientEventTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/client/ClientEventTests.java index beed4effbd..d9e40a377d 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/client/ClientEventTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/client/ClientEventTests.java @@ -9,6 +9,7 @@ import net.minecraft.network.chat.Component; import net.neoforged.api.distmarker.Dist; import net.neoforged.neoforge.client.event.ClientChatEvent; +import net.neoforged.neoforge.client.event.ClientPlayerChangeGameTypeEvent; import net.neoforged.testframework.DynamicTest; import net.neoforged.testframework.annotation.ForEachTest; import net.neoforged.testframework.annotation.TestHolder; @@ -25,4 +26,9 @@ static void playerClientChatEvent(final ClientChatEvent event, final DynamicTest Minecraft.getInstance().tell(() -> test.requestConfirmation(Minecraft.getInstance().player, Component.literal("Was your message modified?"))); } } + + @TestHolder(description = { "Tests if the ClientPlayerChangeGameTypeEvent event is fired", "Will ask the player for confirmation when the player changes their gamemode" }) + static void clientPlayerChangeGameTypeEvent(final ClientPlayerChangeGameTypeEvent event, final DynamicTest test) { + test.requestConfirmation(Minecraft.getInstance().player, Component.literal("Did you just change your game mode from " + event.getCurrentGameType() + " to " + event.getNewGameType() + "?")); + } } diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java index 16fc984567..c8db662eb8 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java @@ -5,17 +5,21 @@ package net.neoforged.neoforge.debug.entity; +import net.minecraft.core.registries.Registries; import net.minecraft.gametest.framework.GameTest; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.ai.attributes.RangedAttribute; import net.minecraft.world.entity.animal.Cow; import net.minecraft.world.entity.animal.Pig; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; +import net.neoforged.neoforge.event.entity.EntityAttributeModificationEvent; import net.neoforged.neoforge.event.entity.EntityTeleportEvent; import net.neoforged.testframework.DynamicTest; import net.neoforged.testframework.annotation.ForEachTest; import net.neoforged.testframework.annotation.TestHolder; import net.neoforged.testframework.gametest.EmptyTemplate; +import net.neoforged.testframework.registration.RegistrationHelper; @ForEachTest(groups = { EntityTests.GROUP + ".event", "event" }) public class EntityEventTests { @@ -50,4 +54,19 @@ static void entityTeleportEvent(final DynamicTest test) { .thenExecute(helper::killAllEntities) .thenSucceed()); } + + @GameTest + @EmptyTemplate(floor = true) + @TestHolder(description = "Tests if the EntityAttributeModificationEvent is fired") + static void entityAttributeModificationEvent(final DynamicTest test, final RegistrationHelper reg) { + final var testAttr = reg.registrar(Registries.ATTRIBUTE).register("test_attribute", () -> new RangedAttribute(reg.modId() + ".test_attr", 1.5D, 0.0D, 1024.0D).setSyncable(true)); + test.framework().modEventBus().addListener((final EntityAttributeModificationEvent event) -> { + event.add(EntityType.DONKEY, testAttr.get()); + }); + + test.onGameTest(helper -> helper.startSequence(() -> helper.spawnWithNoFreeWill(EntityType.DONKEY, 1, 2, 1)) + .thenExecute(donkey -> helper.assertEntityProperty( + donkey, d -> d.getAttribute(testAttr.get()).getValue(), "test attribute", 1.5D)) + .thenSucceed()); + } } diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/entity/living/LivingEntityEventTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/entity/living/LivingEntityEventTests.java index deb2e5e4f3..0a7a80402c 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/entity/living/LivingEntityEventTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/entity/living/LivingEntityEventTests.java @@ -5,17 +5,41 @@ package net.neoforged.neoforge.debug.entity.living; +import java.util.Objects; +import java.util.UUID; +import net.minecraft.core.BlockPos; import net.minecraft.gametest.framework.GameTest; +import net.minecraft.network.chat.Component; import net.minecraft.world.InteractionHand; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal; import net.minecraft.world.entity.animal.allay.Allay; +import net.minecraft.world.entity.monster.Zombie; +import net.minecraft.world.entity.monster.ZombieVillager; +import net.minecraft.world.entity.monster.ZombifiedPiglin; +import net.minecraft.world.entity.npc.Villager; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.projectile.AbstractArrow; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; +import net.minecraft.world.item.alchemy.PotionUtils; +import net.minecraft.world.item.alchemy.Potions; +import net.minecraft.world.level.GameType; +import net.neoforged.fml.util.ObfuscationReflectionHelper; +import net.neoforged.neoforge.event.entity.living.LivingChangeTargetEvent; +import net.neoforged.neoforge.event.entity.living.LivingConversionEvent; +import net.neoforged.neoforge.event.entity.living.LivingEntityUseItemEvent; +import net.neoforged.neoforge.event.entity.living.LivingGetProjectileEvent; import net.neoforged.neoforge.event.entity.living.LivingSwapItemsEvent; +import net.neoforged.neoforge.event.entity.living.ShieldBlockEvent; import net.neoforged.testframework.DynamicTest; import net.neoforged.testframework.annotation.ForEachTest; import net.neoforged.testframework.annotation.TestHolder; import net.neoforged.testframework.gametest.EmptyTemplate; +import net.neoforged.testframework.registration.RegistrationHelper; @ForEachTest(groups = { LivingEntityTests.GROUP + ".event", "event" }) public class LivingEntityEventTests { @@ -42,4 +66,140 @@ static void livingSwapItems(final DynamicTest test) { .thenExecuteAfter(5, () -> helper.killAllEntitiesOfClass(Allay.class)) .thenSucceed()); } + + @GameTest + @EmptyTemplate(floor = true) + @TestHolder(description = "Tests if the LivingConversionEvent is fired and can be successfully cancelled") + static void livingConversionEvent(final DynamicTest test, final RegistrationHelper reg) { + final var shouldConvert = reg.attachments().registerSimpleAttachment("should_convert", () -> true); + + test.eventListeners().forge().addListener((final LivingConversionEvent.Pre event) -> { + if (event.getEntity() instanceof ZombieVillager zombie) { + event.setCanceled(!zombie.getData(shouldConvert)); + } + }); + test.eventListeners().forge().addListener((final LivingConversionEvent.Post event) -> { + if (event.getOutcome() instanceof Villager villager) { + villager.addEffect(new MobEffectInstance(MobEffects.LUCK, 5)); + } + }); + + test.onGameTest(helper -> { + final var converting = helper.spawnWithNoFreeWill(EntityType.ZOMBIE_VILLAGER, 1, 2, 0); + final var nonConverting = helper.spawnWithNoFreeWill(EntityType.ZOMBIE_VILLAGER, 1, 2, 2); + nonConverting.setData(shouldConvert, false); + + final var startConvertingMethod = helper.catchException(() -> ObfuscationReflectionHelper.findMethod(ZombieVillager.class, "startConverting", UUID.class, int.class)); + + helper.startSequence() + .thenExecute(() -> helper.catchException(() -> { + startConvertingMethod.invoke(converting, null, 5); + startConvertingMethod.invoke(nonConverting, null, 5); + })) + // Wait for conversion + .thenIdle(5) + + // The one with the attachment set to false shouldn't have converted + .thenExecute(() -> helper.assertEntityPresent(EntityType.ZOMBIE_VILLAGER, 1, 2, 2)) + + // But the one with the attachment set to true should have + .thenMap(() -> helper.requireEntityAt(EntityType.VILLAGER, 1, 2, 0)) + .thenExecute(() -> helper.assertEntityNotPresent(EntityType.ZOMBIE_VILLAGER, 1, 2, 0)) + + .thenExecute(villager -> helper.assertLivingEntityHasMobEffect( + villager, MobEffects.LUCK, 0)) + .thenSucceed(); + }); + } + + @GameTest + @EmptyTemplate(floor = true) + @TestHolder(description = "Tests if the LivingGetProjectileEvent allows changing the projectile") + static void getProjectileEvent(final DynamicTest test, final RegistrationHelper reg) { + final var shootsFireRes = reg.attachments().registerSimpleAttachment("shoots_fireres", () -> false); + test.eventListeners().forge().addListener((final LivingGetProjectileEvent event) -> { + if (event.getEntity().getData(shootsFireRes)) { + event.setProjectileItemStack(new ItemStack(Items.TIPPED_ARROW)); + PotionUtils.setPotion(event.getProjectileItemStack(), Potions.FIRE_RESISTANCE); + } + }); + + test.onGameTest(helper -> { + final var skelly = helper.spawnWithNoFreeWill(EntityType.SKELETON, 1, 2, 0); + final var pig = helper.spawnWithNoFreeWill(EntityType.PIG, 1, 2, 2); + skelly.addEffect(new MobEffectInstance(MobEffects.WEAKNESS, 100, 10)); + skelly.setData(shootsFireRes, true); + + helper.startSequence() + .thenExecute(() -> skelly.performRangedAttack(pig, 1)) + // Wait for the arrow to reach and the pig to have fire res + .thenWaitUntil(() -> helper.assertLivingEntityHasMobEffect( + pig, MobEffects.FIRE_RESISTANCE, 0)) + .thenSucceed(); + }); + } + + @GameTest + @EmptyTemplate(floor = true, value = "9x9x9") + @TestHolder(description = "Tests if the LivingChangeTargetEvent can be successfully cancelled") + static void setAttackTargetEvent(final DynamicTest test, final RegistrationHelper reg) { + final var specialAggro = reg.attachments().registerSimpleAttachment("special_aggro", () -> false); + test.eventListeners().forge().addListener((final LivingChangeTargetEvent event) -> { + if (event.getTargetType() == LivingChangeTargetEvent.LivingTargetType.MOB_TARGET && + event.getEntity().getData(specialAggro) && event.getNewTarget() instanceof Player player && player.isHolding(Items.STICK)) { + event.setCanceled(true); + } + }); + test.onGameTest(helper -> { + final var zombie = helper.spawn(EntityType.ZOMBIE, 4, 2, 4); + helper.knockbackResistant(zombie); + zombie.setData(specialAggro, true); + + // Make sure that the zombie can only target entities that hurt it + zombie.targetSelector.removeAllGoals(g -> true); + zombie.targetSelector.addGoal(10, new HurtByTargetGoal(zombie).setAlertOthers(ZombifiedPiglin.class)); + + helper.startSequence(() -> helper.makeTickingMockServerPlayerInCorner(GameType.SURVIVAL)) + .thenExecute(player -> player.setItemInHand(InteractionHand.MAIN_HAND, Items.STICK.getDefaultInstance())) + .thenExecute(player -> player.attack(zombie)) + .thenWaitUntil(() -> helper.assertTrue(zombie.getTarget() == null, "Zombie was targeting player")) + + .thenExecute(() -> zombie.setData(specialAggro, false)) + .thenIdle(10) // Increase the zombie tick count + .thenExecute(zombie::setLastHurtByMob) + .thenWaitUntil(player -> helper.assertTrue(zombie.getTarget() != null && zombie.getTarget().is(player), "Zombie wasn't targeting player")) + .thenSucceed(); + }); + } + + @GameTest + @EmptyTemplate(floor = true) + @TestHolder(description = "Tests if the ShieldBlockEvent is fired") + static void shieldBlockEvent(final DynamicTest test) { + test.eventListeners().forge().addListener((final ShieldBlockEvent event) -> { + if (event.getDamageSource().getDirectEntity() instanceof AbstractArrow arrow && event.getEntity() instanceof Zombie zombie && Objects.equals(zombie.getName(), Component.literal("shieldblock"))) { + zombie.setItemSlot(EquipmentSlot.OFFHAND, new ItemStack(Items.STONE)); + event.setBlockedDamage(event.getOriginalBlockedDamage() / 2); + arrow.discard(); + } + }); + + // Make sure that the zombie keeps using the shield + test.eventListeners().forge().addListener((final LivingEntityUseItemEvent event) -> { + if (event.getEntity() instanceof Zombie zombie && Objects.equals(zombie.getName(), Component.literal("shieldblock"))) { + event.setDuration(100); + } + }); + + test.onGameTest(helper -> helper.startSequence(() -> helper.knockbackResistant(helper.spawnWithNoFreeWill(EntityType.ZOMBIE, 1, 2, 2))) + .thenExecute(zombie -> zombie.setCustomName(Component.literal("shieldblock"))) + .thenExecute(zombie -> zombie.setYHeadRot(180)) // Face the zombie towards the skeleton so it can block + + .thenExecute(zombie -> zombie.setItemInHand(InteractionHand.MAIN_HAND, Items.SHIELD.getDefaultInstance())) + .thenExecute(zombie -> zombie.startUsingItem(InteractionHand.MAIN_HAND)) + .thenExecuteAfter(10, zombie -> helper.spawnWithNoFreeWill(EntityType.SKELETON, 1, 2, 0) + .performRangedAttack(zombie, 1f)) + .thenWaitUntil(() -> helper.assertEntityIsHolding(new BlockPos(1, 2, 2), EntityType.ZOMBIE, Items.STONE)) + .thenSucceed()); + } } diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/entity/player/PlayerEventTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/entity/player/PlayerEventTests.java index 3ba0789f93..fc6911902f 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/entity/player/PlayerEventTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/entity/player/PlayerEventTests.java @@ -5,11 +5,14 @@ package net.neoforged.neoforge.debug.entity.player; +import java.util.Objects; +import net.minecraft.commands.Commands; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.gametest.framework.GameTest; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ServerboundInteractPacket; +import net.minecraft.server.players.ServerOpListEntry; import net.minecraft.stats.ServerStatsCounter; import net.minecraft.stats.Stats; import net.minecraft.world.InteractionHand; @@ -26,6 +29,7 @@ import net.minecraft.world.level.block.Blocks; import net.neoforged.bus.api.EventPriority; import net.neoforged.neoforge.event.StatAwardEvent; +import net.neoforged.neoforge.event.entity.player.PermissionsChangedEvent; import net.neoforged.neoforge.event.entity.player.PlayerEvent; import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; import net.neoforged.neoforge.event.entity.player.UseItemOnBlockEvent; @@ -115,6 +119,88 @@ static void entityInteractEvent(final DynamicTest test) { }); } + @GameTest + @EmptyTemplate(floor = true) + @TestHolder(description = "Tests if the ItemPickupEvent fires") + public static void itemPickupEvent(final DynamicTest test) { + test.eventListeners().forge().addListener((final PlayerEvent.ItemPickupEvent event) -> { + if (event.getStack().is(Items.MELON_SEEDS)) { + // If the event is fired and detects pickup of melon seeds, the test will be considered pass + // and the player will get pumpkin seeds too + event.getEntity().addItem(new ItemStack(Items.PUMPKIN_SEEDS)); + test.pass(); + } + }); + + test.onGameTest(helper -> { + // Spawn a player at the centre of the test + final GameTestPlayer player = helper.makeTickingMockServerPlayerInLevel(GameType.SURVIVAL) + .moveToCentre(); + helper.spawnItem(Items.MELON_SEEDS, 1, 2, 1); + + helper.startSequence() + // Wait until the player picked up the seeds + .thenWaitUntil(() -> helper.assertPlayerHasItem(player, Items.MELON_SEEDS)) + // Check for pumpkin seeds in the player's inventory + .thenExecute(() -> helper.assertPlayerHasItem(player, Items.PUMPKIN_SEEDS)) + // All assertions were true, so the test is a success! + .thenSucceed(); + }); + } + + @GameTest + @EmptyTemplate + @TestHolder(description = "Tests if the PlayerChangeGameModeEvent is fired and can modify the outcome") + static void playerChangeGameModeEvent(final DynamicTest test) { + test.eventListeners().forge().addListener((final PlayerEvent.PlayerChangeGameModeEvent event) -> { + // Only affect the players with a custom name to not interfere with other tests + if (!Objects.equals(event.getEntity().getCustomName(), Component.literal("gamemode-changes"))) { + return; + } + + // prevent changing to SURVIVAL + if (event.getNewGameMode() == GameType.SURVIVAL) { + event.setCanceled(true); + } else if (event.getNewGameMode() == GameType.SPECTATOR) { + // when changing to SPECTATOR, change to SURVIVAL instead + event.setNewGameMode(GameType.SURVIVAL); + } + }); + + test.onGameTest(helper -> helper.startSequence(() -> helper.makeTickingMockServerPlayerInLevel(GameType.CREATIVE).moveToCorner()) + .thenExecute(player -> player.setCustomName(Component.literal("gamemode-changes"))) + + .thenExecute(player -> player.setGameMode(GameType.SURVIVAL)) + // Prevent changing to survival + .thenExecute(player -> helper.assertTrue(player.gameMode.getGameModeForPlayer() == GameType.CREATIVE, "Event was not cancelled")) + + // Actually change to spectator + .thenExecute(player -> player.setGameMode(GameType.SPECTATOR)) + .thenExecute(player -> helper.assertTrue(player.gameMode.getGameModeForPlayer() == GameType.SURVIVAL, "Event did not modify game mode")) + .thenSucceed()); + } + + @GameTest + @EmptyTemplate + @TestHolder(description = "Tests if the PermissionsChangedEvent is fired, by preventing players from being de-op'd") + static void permissionsChangedEvent(final DynamicTest test) { + test.eventListeners().forge().addListener((final PermissionsChangedEvent event) -> { + if (Objects.equals(event.getEntity().getCustomName(), Component.literal("permschangedevent")) && event.getOldLevel() == Commands.LEVEL_ADMINS) { + event.setCanceled(true); + test.pass(); + } + }); + + test.onGameTest(helper -> helper.startSequence(() -> helper.makeTickingMockServerPlayerInLevel(GameType.CREATIVE).moveToCorner()) + .thenExecute(player -> player.setCustomName(Component.literal("permschangedevent"))) + // Make sure the player isn't OP by default + .thenExecute(player -> player.getServer().getPlayerList().getOps().add(new ServerOpListEntry( + player.getGameProfile(), Commands.LEVEL_ADMINS, true))) + .thenExecute(player -> player.getServer().getPlayerList().deop(player.getGameProfile())) + .thenExecute(player -> helper.assertTrue(player.getServer().getProfilePermissions(player.getGameProfile()) == Commands.LEVEL_ADMINS, "Player was de-op'd")) + .thenSucceed()); + } + @GameTest @EmptyTemplate @TestHolder(description = "Tests if the StatsAwardEvent properly modifies stats stored per player") diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/item/ItemEventTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/item/ItemEventTests.java new file mode 100644 index 0000000000..4b5c956655 --- /dev/null +++ b/tests/src/main/java/net/neoforged/neoforge/debug/item/ItemEventTests.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.debug.item; + +import net.minecraft.gametest.framework.GameTest; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.GameType; +import net.neoforged.neoforge.event.ItemAttributeModifierEvent; +import net.neoforged.testframework.DynamicTest; +import net.neoforged.testframework.annotation.ForEachTest; +import net.neoforged.testframework.annotation.TestHolder; +import net.neoforged.testframework.gametest.EmptyTemplate; + +@ForEachTest(groups = { ItemTests.GROUP + ".event", "event" }) +public class ItemEventTests { + @GameTest + @EmptyTemplate(floor = true) + @TestHolder(description = "Tests if the ItemAttributeModifierEvent allows modifying attributes") + static void itemAttributeModifier(final DynamicTest test) { + test.eventListeners().forge().addListener((final ItemAttributeModifierEvent event) -> { + if (event.getSlotType() == EquipmentSlot.MAINHAND && event.getItemStack().getItem() == Items.APPLE) { + event.addModifier(Attributes.ARMOR, new AttributeModifier(test.createModId(), 10f, AttributeModifier.Operation.ADDITION)); + } else if (event.getSlotType() == EquipmentSlot.CHEST && event.getItemStack().is(Items.GOLDEN_CHESTPLATE)) { + event.clearModifiers(); + } + }); + + test.onGameTest(helper -> helper.startSequence(() -> helper.makeTickingMockServerPlayerInCorner(GameType.SURVIVAL)) + .thenExecute(player -> player.setItemSlot(EquipmentSlot.CHEST, Items.GOLDEN_CHESTPLATE.getDefaultInstance())) + .thenExecuteAfter(1, player -> helper.assertEntityProperty( + player, + LivingEntity::getArmorValue, + "armor", + 0)) // Expect the chestplate to give no armor + + .thenExecute(player -> player.setItemSlot(EquipmentSlot.MAINHAND, Items.APPLE.getDefaultInstance())) + .thenExecuteAfter(1, player -> helper.assertEntityProperty( + player, + LivingEntity::getArmorValue, + "armor", + 10)) // 10 armor from the apple in main hand + .thenSucceed()); + } +} diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/item/ItemTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/item/ItemTests.java index e1be2c2419..aa8a202d32 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/item/ItemTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/item/ItemTests.java @@ -21,6 +21,8 @@ import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResultHolder; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.MobCategory; import net.minecraft.world.entity.ai.attributes.Attribute; import net.minecraft.world.entity.ai.attributes.AttributeInstance; @@ -28,6 +30,8 @@ import net.minecraft.world.entity.animal.Cow; import net.minecraft.world.entity.animal.Pig; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.ArmorMaterials; import net.minecraft.world.item.CreativeModeTabs; import net.minecraft.world.item.DispensibleContainerItem; import net.minecraft.world.item.Item; @@ -171,4 +175,30 @@ static void itemCustomRarity(final DynamicTest test, final RegistrationHelper re style.getColor().getValue() == ChatFormatting.DARK_AQUA.getColor(), "custom rarity did not make component italic")) .thenSucceed()); } + + @GameTest + @TestHolder(description = "Adds snow boots that allow a player to walk on powdered snow as long as they have less than half health") + static void snowBoots(final DynamicTest test, final RegistrationHelper reg) { + test.registerGameTestTemplate(StructureTemplateBuilder.withSize(3, 5, 3) + .fill(0, 0, 0, 2, 0, 2, Blocks.IRON_BLOCK) + .fill(0, 1, 0, 2, 1, 2, Blocks.POWDER_SNOW)); + + final var snowBoots = reg.items().register("snow_boots", () -> new ArmorItem(ArmorMaterials.DIAMOND, ArmorItem.Type.BOOTS, (new Item.Properties())) { + @Override + public boolean canWalkOnPowderedSnow(ItemStack stack, LivingEntity wearer) { + return wearer.getHealth() < wearer.getMaxHealth() / 2; + } + }).withLang("Snow Boots").tab(CreativeModeTabs.TOOLS_AND_UTILITIES); + + test.onGameTest(helper -> helper.startSequence(() -> helper.spawnWithNoFreeWill(EntityType.PIG, 1, 3, 1)) + .thenExecute(pig -> pig.setItemSlot(EquipmentSlot.FEET, snowBoots.get().getDefaultInstance())) + .thenExecute(pig -> pig.setHealth(pig.getMaxHealth() / 2 - 1)) + // Pig shouldn't have fallen + .thenExecuteAfter(20, () -> helper.assertEntityPresent(EntityType.PIG, 1, 3, 1)) + + // Back to max health so falling time + .thenExecute(pig -> pig.setHealth(pig.getMaxHealth())) + .thenWaitUntil(() -> helper.assertEntityPresent(EntityType.PIG, 1, 2, 1)) + .thenSucceed()); + } } diff --git a/tests/src/main/java/net/neoforged/neoforge/oldtest/entity/AddEntityAttributeTest.java b/tests/src/main/java/net/neoforged/neoforge/oldtest/entity/AddEntityAttributeTest.java deleted file mode 100644 index d3b55df43d..0000000000 --- a/tests/src/main/java/net/neoforged/neoforge/oldtest/entity/AddEntityAttributeTest.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.neoforged.neoforge.oldtest.entity; - -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.world.entity.ai.attributes.Attribute; -import net.minecraft.world.entity.ai.attributes.RangedAttribute; -import net.neoforged.bus.api.IEventBus; -import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.common.Mod; -import net.neoforged.neoforge.event.entity.EntityAttributeModificationEvent; -import net.neoforged.neoforge.registries.DeferredHolder; -import net.neoforged.neoforge.registries.DeferredRegister; - -@Mod("add_entity_attribute_test") -public class AddEntityAttributeTest { - public static final boolean ENABLE = true; - private static final DeferredRegister ATTRIBUTES = DeferredRegister.create(BuiltInRegistries.ATTRIBUTE, "add_entity_attribute_test"); - public static final DeferredHolder TEST_ATTR = ATTRIBUTES.register("test_attr", () -> new RangedAttribute("neoforge.test_attr", 1.0D, 0.0D, 1024.0D).setSyncable(true)); - - public AddEntityAttributeTest(IEventBus modEventBus) { - if (ENABLE) { - ATTRIBUTES.register(modEventBus); - modEventBus.register(this); - } - } - - @SubscribeEvent - public void entityAttributeSetup(EntityAttributeModificationEvent event) { - event.getTypes().forEach(entityType -> { - if (!event.has(entityType, TEST_ATTR.get())) { - event.add(entityType, TEST_ATTR.get()); - } - }); - } -} diff --git a/tests/src/main/java/net/neoforged/neoforge/oldtest/entity/living/LivingConversionEventTest.java b/tests/src/main/java/net/neoforged/neoforge/oldtest/entity/living/LivingConversionEventTest.java deleted file mode 100644 index 662a2a9c80..0000000000 --- a/tests/src/main/java/net/neoforged/neoforge/oldtest/entity/living/LivingConversionEventTest.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.neoforged.neoforge.oldtest.entity.living; - -import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.effect.MobEffects; -import net.minecraft.world.entity.monster.piglin.Piglin; -import net.minecraft.world.entity.npc.Villager; -import net.neoforged.fml.common.Mod; -import net.neoforged.neoforge.common.NeoForge; -import net.neoforged.neoforge.event.entity.living.LivingConversionEvent; - -@Mod("living_conversion_event_test") -public class LivingConversionEventTest { - public LivingConversionEventTest() { - NeoForge.EVENT_BUS.addListener(this::canLivingConversion); - NeoForge.EVENT_BUS.addListener(this::onLivingConversion); - } - - public void canLivingConversion(LivingConversionEvent.Pre event) { - if (event.getEntity() instanceof Piglin) { - event.setCanceled(true); - event.setConversionTimer(0); - } - } - - public void onLivingConversion(LivingConversionEvent.Post event) { - if (event.getEntity() instanceof Villager) - event.getEntity().addEffect(new MobEffectInstance(MobEffects.LUCK, 20)); - } -} diff --git a/tests/src/main/java/net/neoforged/neoforge/oldtest/entity/living/LivingGetProjectileEventTest.java b/tests/src/main/java/net/neoforged/neoforge/oldtest/entity/living/LivingGetProjectileEventTest.java deleted file mode 100644 index 0448a45a0b..0000000000 --- a/tests/src/main/java/net/neoforged/neoforge/oldtest/entity/living/LivingGetProjectileEventTest.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.neoforged.neoforge.oldtest.entity.living; - -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.neoforged.fml.common.Mod; -import net.neoforged.neoforge.common.NeoForge; -import net.neoforged.neoforge.event.entity.living.LivingGetProjectileEvent; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -@Mod("living_get_projectile_event_test") -public class LivingGetProjectileEventTest { - public static final boolean ENABLED = true; - public static final Logger LOGGER = LogManager.getLogger(); - - public LivingGetProjectileEventTest() { - if (ENABLED) { - NeoForge.EVENT_BUS.addListener(this::onLivingGetProjectile); - } - } - - public void onLivingGetProjectile(LivingGetProjectileEvent event) { - LOGGER.info("{} about to fire {} with a {}", event.getEntity(), event.getProjectileItemStack(), event.getProjectileWeaponItemStack()); - - // for this test, we're checking if the player has a spectral arrow itemstack in their offhand and if they're firing a normal arrow. - // if they do, we're going to use that itemstack. if not, we will create a spectral arrow itemstack - // this demonstrates the usage of specific itemstacks with this event. you can use specific itemstacks from the player's inventory in this similar style - if (event.getEntity() instanceof Player player && event.getProjectileItemStack().getItem() == Items.ARROW) { - ItemStack offhandItem = player.getOffhandItem(); - event.setProjectileItemStack(offhandItem.getItem() == Items.SPECTRAL_ARROW ? offhandItem : new ItemStack(Items.SPECTRAL_ARROW)); - } - } -} diff --git a/tests/src/main/java/net/neoforged/neoforge/oldtest/entity/living/LivingSetAttackTargetEventTest.java b/tests/src/main/java/net/neoforged/neoforge/oldtest/entity/living/LivingSetAttackTargetEventTest.java deleted file mode 100644 index 89b5d9eca6..0000000000 --- a/tests/src/main/java/net/neoforged/neoforge/oldtest/entity/living/LivingSetAttackTargetEventTest.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.neoforged.neoforge.oldtest.entity.living; - -import net.minecraft.world.entity.monster.piglin.AbstractPiglin; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.Items; -import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.common.Mod; -import net.neoforged.neoforge.common.NeoForge; -import net.neoforged.neoforge.event.entity.living.LivingChangeTargetEvent; - -@Mod("living_set_attack_target_event_test") -public class LivingSetAttackTargetEventTest { - public static final boolean ENABLE = true; - - public LivingSetAttackTargetEventTest() { - if (ENABLE) { - NeoForge.EVENT_BUS.register(this); - } - } - - @SubscribeEvent - public void onLivingChangeTargetEvent(LivingChangeTargetEvent event) { - // Prevents the piglin from attacking the player if they hold a stick in their hands. - if (event.getNewTarget() instanceof Player player && event.getEntity() instanceof AbstractPiglin piglin && player.getMainHandItem().getItem() == Items.STICK) { - event.setCanceled(true); - } - } -} diff --git a/tests/src/main/java/net/neoforged/neoforge/oldtest/entity/player/PermissionsChangedEventTest.java b/tests/src/main/java/net/neoforged/neoforge/oldtest/entity/player/PermissionsChangedEventTest.java deleted file mode 100644 index 7bc33d67e9..0000000000 --- a/tests/src/main/java/net/neoforged/neoforge/oldtest/entity/player/PermissionsChangedEventTest.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.neoforged.neoforge.oldtest.entity.player; - -import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.common.Mod; -import net.neoforged.neoforge.event.entity.player.PermissionsChangedEvent; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -@Mod("permissions_changed_event_test") -@Mod.EventBusSubscriber -public class PermissionsChangedEventTest { - private static final Logger LOGGER = LogManager.getLogger(); - - @SubscribeEvent - public static void onPermissionChanged(PermissionsChangedEvent event) { - LOGGER.info("{} permission level changed to {} from {}", - event.getEntity().getName().getString(), - event.getNewLevel(), - event.getOldLevel()); - } -} diff --git a/tests/src/main/java/net/neoforged/neoforge/oldtest/entity/player/PlayerGameModeEventTest.java b/tests/src/main/java/net/neoforged/neoforge/oldtest/entity/player/PlayerGameModeEventTest.java deleted file mode 100644 index ee45a87a31..0000000000 --- a/tests/src/main/java/net/neoforged/neoforge/oldtest/entity/player/PlayerGameModeEventTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.neoforged.neoforge.oldtest.entity.player; - -import net.minecraft.world.level.GameType; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.common.Mod; -import net.neoforged.neoforge.client.event.ClientPlayerChangeGameTypeEvent; -import net.neoforged.neoforge.event.entity.player.PlayerEvent; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -@Mod("player_game_mode_event_test") -@Mod.EventBusSubscriber() -public class PlayerGameModeEventTest { - private static final boolean ENABLE = false; - private static final Logger LOGGER = LogManager.getLogger(PlayerGameModeEventTest.class); - - @SubscribeEvent - public static void onPlayerChangeGameModeEvent(PlayerEvent.PlayerChangeGameModeEvent event) { - if (!ENABLE) return; - LOGGER.info("{} changed game mode. Current GameType: {}. New Game Type: {}", event.getEntity(), event.getCurrentGameMode(), event.getNewGameMode()); - // prevent changing to SURVIVAL - if (event.getNewGameMode() == GameType.SURVIVAL) { - event.setCanceled(true); - } else if (event.getNewGameMode() == GameType.SPECTATOR) { - // when changing to SPECTATOR, change to SURVIVAL instead - event.setNewGameMode(GameType.SURVIVAL); - } - } - - @Mod.EventBusSubscriber(modid = "player_game_mode_event_test", value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.FORGE) - public static class PlayerGameModeEventTestClientForgeEvents { - @SubscribeEvent - public static void onClientPlayerChangeGameModeEvent(ClientPlayerChangeGameTypeEvent event) { - if (!ENABLE) return; - LOGGER.info("Client notified of changed game mode from '{}'. Current GameType: {}. New Game Type: {}", event.getInfo().getProfile(), event.getCurrentGameType(), event.getNewGameType()); - } - } -} diff --git a/tests/src/main/java/net/neoforged/neoforge/oldtest/item/CustomMobBucketTest.java b/tests/src/main/java/net/neoforged/neoforge/oldtest/item/CustomMobBucketTest.java deleted file mode 100644 index 7c8b56c613..0000000000 --- a/tests/src/main/java/net/neoforged/neoforge/oldtest/item/CustomMobBucketTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.neoforged.neoforge.oldtest.item; - -import net.minecraft.sounds.SoundEvents; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.item.CreativeModeTabs; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.MobBucketItem; -import net.minecraft.world.level.material.Fluids; -import net.neoforged.bus.api.IEventBus; -import net.neoforged.fml.common.Mod; -import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent; -import net.neoforged.neoforge.registries.DeferredItem; -import net.neoforged.neoforge.registries.DeferredRegister; - -@Mod(CustomMobBucketTest.MODID) -public class CustomMobBucketTest { - public static final String MODID = "custom_mob_bucket_test"; - public static final DeferredRegister.Items ITEMS = DeferredRegister.createItems(MODID); - - public static final boolean ENABLED = true; - - public static final DeferredItem COW_BUCKET = ITEMS.register("cow_bucket", () -> new MobBucketItem( - () -> EntityType.COW, - () -> Fluids.WATER, - () -> SoundEvents.BUCKET_EMPTY_FISH, - (new Item.Properties()).stacksTo(1))); - - public CustomMobBucketTest(IEventBus modEventBus) { - if (ENABLED) { - ITEMS.register(modEventBus); - modEventBus.addListener(this::addCreative); - } - } - - private void addCreative(BuildCreativeModeTabContentsEvent event) { - if (event.getTabKey() == CreativeModeTabs.INGREDIENTS) - event.accept(COW_BUCKET); - } -} diff --git a/tests/src/main/java/net/neoforged/neoforge/oldtest/item/ItemAttributeModifierTest.java b/tests/src/main/java/net/neoforged/neoforge/oldtest/item/ItemAttributeModifierTest.java deleted file mode 100644 index 116dcd1759..0000000000 --- a/tests/src/main/java/net/neoforged/neoforge/oldtest/item/ItemAttributeModifierTest.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.neoforged.neoforge.oldtest.item; - -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.ai.attributes.AttributeModifier; -import net.minecraft.world.entity.ai.attributes.AttributeModifier.Operation; -import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.Items; -import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.common.Mod; -import net.neoforged.neoforge.event.ItemAttributeModifierEvent; - -@Mod(ItemAttributeModifierTest.MOD_ID) -@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.FORGE, modid = ItemAttributeModifierTest.MOD_ID) -public class ItemAttributeModifierTest { - public static final String MOD_ID = "item_modifier_test"; - public static final boolean ENABLED = true; - private static final AttributeModifier MODIFIER = new AttributeModifier(MOD_ID, 10f, Operation.ADDITION); - - @SubscribeEvent - public static void onItemAttribute(ItemAttributeModifierEvent event) { - if (ENABLED && event.getSlotType() == EquipmentSlot.MAINHAND) { - final Item item = event.getItemStack().getItem(); - if (item == Items.APPLE) { - event.addModifier(Attributes.ARMOR, MODIFIER); - } else if (item == Items.GOLDEN_SWORD) { - event.clearModifiers(); - } - } - } -} diff --git a/tests/src/main/java/net/neoforged/neoforge/oldtest/item/ShieldBlockTest.java b/tests/src/main/java/net/neoforged/neoforge/oldtest/item/ShieldBlockTest.java deleted file mode 100644 index 5e7b356cb3..0000000000 --- a/tests/src/main/java/net/neoforged/neoforge/oldtest/item/ShieldBlockTest.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.neoforged.neoforge.oldtest.item; - -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.entity.projectile.AbstractArrow; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.common.Mod; -import net.neoforged.neoforge.event.entity.living.ShieldBlockEvent; - -/** - * The ShieldBlockTest is the test mod for the ShieldBlockEvent. - * If successful, this handler will trigger when an arrow is blocked by a player. - * The event will give the arrow to the player, and make the player receive half of the damage (instead of zero damage). - * Note this just gives them a normal arrow, retrieving the true arrow requires some reflection. - */ -@Mod(ShieldBlockTest.MOD_ID) -@Mod.EventBusSubscriber -public class ShieldBlockTest { - static final String MOD_ID = "shield_block_event"; - - @SubscribeEvent - public static void shieldBlock(ShieldBlockEvent event) { - if (event.getDamageSource().getDirectEntity() instanceof AbstractArrow arrow && event.getEntity() instanceof Player player) { - player.getInventory().add(new ItemStack(Items.ARROW)); - event.setBlockedDamage(event.getOriginalBlockedDamage() / 2); - arrow.discard(); - } - } -} diff --git a/tests/src/main/java/net/neoforged/neoforge/oldtest/item/SnowBootsTest.java b/tests/src/main/java/net/neoforged/neoforge/oldtest/item/SnowBootsTest.java deleted file mode 100644 index 31a0b62451..0000000000 --- a/tests/src/main/java/net/neoforged/neoforge/oldtest/item/SnowBootsTest.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.neoforged.neoforge.oldtest.item; - -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.item.ArmorItem; -import net.minecraft.world.item.ArmorMaterials; -import net.minecraft.world.item.CreativeModeTabs; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.neoforged.bus.api.IEventBus; -import net.neoforged.fml.common.Mod; -import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent; -import net.neoforged.neoforge.registries.DeferredItem; -import net.neoforged.neoforge.registries.DeferredRegister; - -@Mod(SnowBootsTest.MODID) -public class SnowBootsTest { - public static final String MODID = "snow_boots_test"; - public static final DeferredRegister.Items ITEMS = DeferredRegister.createItems(MODID); - - public static DeferredItem SNOW_BOOTS = ITEMS.register("snow_boots", () -> new ArmorItem(ArmorMaterials.DIAMOND, ArmorItem.Type.BOOTS, (new Item.Properties())) { - @Override - public boolean canWalkOnPowderedSnow(ItemStack stack, LivingEntity wearer) { - return wearer.getHealth() < 10; - } - }); - - public SnowBootsTest(IEventBus modEventBus) { - ITEMS.register(modEventBus); - modEventBus.addListener(this::addCreative); - } - - private void addCreative(BuildCreativeModeTabContentsEvent event) { - if (event.getTabKey() == CreativeModeTabs.COMBAT) - event.accept(SNOW_BOOTS); - } -} diff --git a/tests/src/main/resources/META-INF/mods.toml b/tests/src/main/resources/META-INF/mods.toml index cd1e2137ae..103a4030b3 100644 --- a/tests/src/main/resources/META-INF/mods.toml +++ b/tests/src/main/resources/META-INF/mods.toml @@ -88,32 +88,22 @@ modId="raid_enum_test" [[mods]] modId="custom_elytra_test" [[mods]] -modId="snow_boots_test" -[[mods]] modId="stop_using_item" [[mods]] modId="scaffolding_test" [[mods]] modId="forge_chunk_manager_test" [[mods]] -modId="living_conversion_event_test" -[[mods]] -modId="player_game_mode_event_test" -[[mods]] modId="forge_codecs_test" [[mods]] modId="render_local_player_test" [[mods]] modId="custom_sound_type_test" [[mods]] -modId="item_modifier_test" -[[mods]] modId="custom_signs_test" [[mods]] modId="worldgen_registry_desync_test" [[mods]] -modId="add_entity_attribute_test" -[[mods]] modId="fake_player_test" [[mods]] modId="text_linear_filtering_test" @@ -136,8 +126,6 @@ modId="spawn_placement_test" [[mods]] modId="redstone_sided_connectivity_test" [[mods]] -modId="permissions_changed_event_test" -[[mods]] modId="custom_shield_test" [[mods]] modId="add_pack_finders_test" @@ -150,16 +138,12 @@ modId="permissiontest" [[mods]] modId="part_entity_test" [[mods]] -modId="custom_mob_bucket_test" -[[mods]] modId="custom_armor_model_test" [[mods]] modId="duplicate_optional_tag_test" [[mods]] modId="custom_particle_type_test" [[mods]] -modId="shield_block_event" -[[mods]] modId="renderable_test" [[mods]] modId="ingredient_invalidation" @@ -182,8 +166,6 @@ modId="recipe_book_extension_test" [[mods]] modId="hide_neighbor_face_test" [[mods]] -modId="living_get_projectile_event_test" -[[mods]] modId="server_world_creation_test" [[mods]] modId="valid_railshape_test" @@ -202,8 +184,6 @@ modId="emissive_elements_test" [[mods]] modId="anvil_update_event_fix" [[mods]] -modId="living_set_attack_target_event_test" -[[mods]] modId="item_use_animation_test" [[mods]] modId="custom_color_resolver_test"