diff --git a/src/gametest/java/io/nihlen/scriptschunkloaders/ScriptsChunkLoadersGameTest.java b/src/gametest/java/io/nihlen/scriptschunkloaders/ScriptsChunkLoadersGameTest.java index 819b992..4577a69 100644 --- a/src/gametest/java/io/nihlen/scriptschunkloaders/ScriptsChunkLoadersGameTest.java +++ b/src/gametest/java/io/nihlen/scriptschunkloaders/ScriptsChunkLoadersGameTest.java @@ -1,7 +1,7 @@ package io.nihlen.scriptschunkloaders; import net.fabricmc.fabric.api.gametest.v1.GameTest; - +import net.minecraft.block.entity.SculkSensorBlockEntity; import net.minecraft.component.DataComponentTypes; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; @@ -10,7 +10,6 @@ import net.minecraft.test.TestContext; import net.minecraft.text.Text; import net.minecraft.util.math.BlockPos; - import java.util.Objects; import java.util.function.Function; @@ -40,11 +39,18 @@ * - Minecart registers, unregisters and registers again * * - Minecart does not register with empty dispenser +* +* - Minecart registers with sculk sensor +* +* - Minecart unregisters with sculk sensor * */ +@SuppressWarnings("unused") public class ScriptsChunkLoadersGameTest { String defaultName = "Chunk Loader"; String customItemName = "My Custom Item"; + Integer startLoaderFrequency = 6; + Integer stopLoaderFrequency = 5; Function getCustomName = entity -> { var customName = entity.getCustomName(); @@ -351,4 +357,72 @@ public void doesNotRegisterWithEmptyDispenser(TestContext context) { context.complete(); }); } + + @GameTest(structure = "scl_tests:sculk_activate") + public void registerWithResonance(TestContext context) { + clearTest(context); + + context.spawnEntity(EntityType.MINECART, 2, 1, 2); + context.removeBlock(new BlockPos(3, 1, 2)); + context.putAndRemoveRedstoneBlock(new BlockPos(1, 1, 1), 1); + + context.waitAndRun(15, () -> { + BlockPos pos = new BlockPos( 4, 1, 2); + SculkSensorBlockEntity sensor = context.getBlockEntity(pos, SculkSensorBlockEntity.class); + + if (sensor.getLastVibrationFrequency() != startLoaderFrequency) { + throw context.createError(pos, String.format( + "Expected a vibration frequency of %s, instead got %s", + startLoaderFrequency, + sensor.getLastVibrationFrequency() + )); + } + + context.expectEntityWithData( + new BlockPos(2, 1, 2), + EntityType.MINECART, + getCustomName, + defaultName + ); + context.complete(); + }); + } + + @GameTest(structure = "scl_tests:sculk_activate") + public void unregisterWithResonance(TestContext context) { + clearTest(context); + + context.spawnEntity(EntityType.MINECART, 2, 1, 2); + context.putAndRemoveRedstoneBlock(new BlockPos(1, 1, 1), 1); + + context.waitAndRun(4, () -> { + context.expectEntityWithData(new BlockPos(2, 1, 2), EntityType.MINECART, getCustomName, defaultName); + context.removeBlock(new BlockPos(3, 1, 2)); + + context.waitAndRun(4, () -> { + context.putAndRemoveRedstoneBlock(new BlockPos(1, 1, 1), 1); + + context.waitAndRun(8, () -> { + BlockPos pos = new BlockPos( 4, 1, 2); + SculkSensorBlockEntity sensor = context.getBlockEntity(pos, SculkSensorBlockEntity.class); + + if (sensor.getLastVibrationFrequency() != stopLoaderFrequency) { + throw context.createError(pos, String.format( + "Expected a vibration frequency of %s, instead got %s", + stopLoaderFrequency, + sensor.getLastVibrationFrequency() + )); + } + + context.expectEntityWithData( + new BlockPos(2, 1, 2), + EntityType.MINECART, + getCustomName, + null + ); + context.complete(); + }); + }); + }); + } } \ No newline at end of file diff --git a/src/gametest/resources/data/scl_tests/structure/sculk_activate.nbt b/src/gametest/resources/data/scl_tests/structure/sculk_activate.nbt new file mode 100644 index 0000000..75aba94 Binary files /dev/null and b/src/gametest/resources/data/scl_tests/structure/sculk_activate.nbt differ diff --git a/src/main/java/io/nihlen/scriptschunkloaders/ScriptsChunkLoadersMod.java b/src/main/java/io/nihlen/scriptschunkloaders/ScriptsChunkLoadersMod.java index 84810be..70b4018 100644 --- a/src/main/java/io/nihlen/scriptschunkloaders/ScriptsChunkLoadersMod.java +++ b/src/main/java/io/nihlen/scriptschunkloaders/ScriptsChunkLoadersMod.java @@ -2,6 +2,13 @@ import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; +import net.fabricmc.fabric.api.gamerule.v1.GameRuleFactory; +import net.fabricmc.fabric.api.gamerule.v1.GameRuleRegistry; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.world.BlockView; +import net.minecraft.world.ChunkRegion; +import net.minecraft.world.GameRules; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,6 +21,8 @@ public class ScriptsChunkLoadersMod implements ModInitializer { public static final Logger LOGGER = LoggerFactory.getLogger(MODID); public static final ChunkLoaderManager CHUNK_LOADER_MANAGER = new ChunkLoaderManager(); + public static final GameRules.Key ALWAYS_SHOW_LOADER_NAME = GameRuleRegistry.register("alwaysShowLoaderName", GameRules.Category.MISC, GameRuleFactory.createBooleanRule(true)); + @Override public void onInitialize() { // This code runs as soon as Minecraft is in a mod-load-ready state. @@ -22,4 +31,25 @@ public void onInitialize() { ServerLifecycleEvents.SERVER_STARTED.register(CHUNK_LOADER_MANAGER::initialize); } + + public static boolean isCustomNameVisible(BlockView world) { + GameRules rules = null; + + if (world instanceof ServerWorld serverWorld) + rules = serverWorld.getGameRules(); + else if (world instanceof ChunkRegion chunkRegion) + { + MinecraftServer server = chunkRegion.getServer(); + + if (server != null) { + rules = server.getGameRules(); + } + } + + if (rules != null) { + return rules.getBoolean(ALWAYS_SHOW_LOADER_NAME); + } + + return true; + } } diff --git a/src/main/java/io/nihlen/scriptschunkloaders/mixin/AbstractMinecartEntityMixin.java b/src/main/java/io/nihlen/scriptschunkloaders/mixin/AbstractMinecartEntityMixin.java index 9351e5c..c979a5c 100644 --- a/src/main/java/io/nihlen/scriptschunkloaders/mixin/AbstractMinecartEntityMixin.java +++ b/src/main/java/io/nihlen/scriptschunkloaders/mixin/AbstractMinecartEntityMixin.java @@ -4,7 +4,6 @@ import net.minecraft.entity.vehicle.*; import net.minecraft.world.TeleportTarget; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -28,9 +27,7 @@ public abstract class AbstractMinecartEntityMixin extends Entity implements Mine private boolean isChunkLoader = false; @Unique private int particleTicker = 0; - @Unique - private final int particleInterval = 3; - @Unique + @Unique private ChunkPos lastChunkPos = null; public AbstractMinecartEntityMixin(EntityType type, World world) { @@ -62,7 +59,7 @@ private void injectConstructor(CallbackInfo callbackInfo) { if (minecartType == EntityType.CHEST_MINECART) { //noinspection DataFlowIssue - We're sure this is a chest because of the if statement. var entity = (ChestMinecartEntity)(Object)this; - var firstSlot = entity.getInventory().get(0); + var firstSlot = entity.getInventory().getFirst(); var hasCustomName = firstSlot.get(DataComponentTypes.CUSTOM_NAME) != null; @@ -71,21 +68,23 @@ private void injectConstructor(CallbackInfo callbackInfo) { scripts_chunk_loaders$setChunkLoaderName(name); return; } - }; + } - scripts_chunk_loaders$setChunkLoaderName("Chunk Loader"); + scripts_chunk_loaders$setChunkLoaderName("Chunk Loader"); } public void scripts_chunk_loaders$setChunkLoaderName(String name) { var nameText = Text.literal(name); this.setCustomName(nameText); - this.setCustomNameVisible(true); + this.setCustomNameVisible(ScriptsChunkLoadersMod.isCustomNameVisible(getWorld())); } public void scripts_chunk_loaders$stopChunkLoader() { scripts_chunk_loaders$stopChunkLoader(false); this.lastChunkPos = null; } + + @Unique public void scripts_chunk_loaders$stopChunkLoader(Boolean keepName) { this.isChunkLoader = false; @@ -147,7 +146,7 @@ public Entity teleportTo(TeleportTarget teleportTarget) { @Unique private void tickParticles() { this.particleTicker += 1; - if (this.particleTicker >= particleInterval) { + if (this.particleTicker >= 3) { this.particleTicker = 0; this.spawnParticles(); } diff --git a/src/main/java/io/nihlen/scriptschunkloaders/mixin/DispenserBlockMixin.java b/src/main/java/io/nihlen/scriptschunkloaders/mixin/DispenserBlockMixin.java index 99df91c..c41573a 100644 --- a/src/main/java/io/nihlen/scriptschunkloaders/mixin/DispenserBlockMixin.java +++ b/src/main/java/io/nihlen/scriptschunkloaders/mixin/DispenserBlockMixin.java @@ -13,6 +13,7 @@ import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; +import net.minecraft.world.event.GameEvent; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -61,15 +62,30 @@ private void toggleMinecraftChunkLoader(ServerWorld world, BlockState state, Blo BlockPos blockPos = pos.offset(state.get(DispenserBlock.FACING)); List list = world.getEntitiesByClass(AbstractMinecartEntity.class, new Box(blockPos), EntityPredicates.VALID_ENTITY); + boolean stoppedLoader = false; + boolean startedLoader = false; + for (AbstractMinecartEntity entity : list) { MinecartEntityExt cart = (MinecartEntityExt)entity; if (cart.scripts_chunk_loaders$isChunkLoader()) { cart.scripts_chunk_loaders$stopChunkLoader(); + + stoppedLoader = true; } else { cart.scripts_chunk_loaders$startChunkLoader(); cart.scripts_chunk_loaders$setChunkLoaderNameFromInventory(); + + startedLoader = true; } } + + if (startedLoader) { + world.emitGameEvent(GameEvent.RESONATE_6, pos, GameEvent.Emitter.of(state)); + } + + if (stoppedLoader) { + world.emitGameEvent(GameEvent.RESONATE_5, pos, GameEvent.Emitter.of(state)); + } } }