/* * Decompiled with CFR 0.152. * * Could not load the following classes: * javax.annotation.Nullable * net.minecraft.block.BlockState * net.minecraft.entity.player.PlayerEntity * net.minecraft.entity.player.PlayerInventory * net.minecraft.entity.player.ServerPlayerEntity * net.minecraft.inventory.container.Container * net.minecraft.inventory.container.INamedContainerProvider * net.minecraft.nbt.CompoundNBT * net.minecraft.nbt.INBT * net.minecraft.network.NetworkManager * net.minecraft.network.play.server.SUpdateTileEntityPacket * net.minecraft.tileentity.ITickableTileEntity * net.minecraft.tileentity.TileEntity * net.minecraft.tileentity.TileEntityType * net.minecraft.util.math.BlockPos * net.minecraft.util.math.vector.Vector3d * net.minecraft.util.text.ITextComponent * net.minecraft.util.text.TranslationTextComponent * net.minecraftforge.fml.network.PacketDistributor */ package com.example.soundmod.gameplay.tile; import com.example.soundmod.common.ActivationMode; import com.example.soundmod.common.RedstoneMode; import com.example.soundmod.common.ScenarioQueue; import com.example.soundmod.common.SoundSettings; import com.example.soundmod.common.ZoneIntersectionPolicy; import com.example.soundmod.common.ZoneShape; import com.example.soundmod.core.SoundDebug; import com.example.soundmod.gameplay.container.SoundPlayerContainer; import com.example.soundmod.net.NetworkHandler; import com.example.soundmod.net.packet.S2CBlockStateSyncPacket; import com.example.soundmod.net.packet.S2CPlaySoundPacket; import com.example.soundmod.net.packet.S2CZoneStateSyncPacket; import com.example.soundmod.registry.ModTileEntities; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import javax.annotation.Nullable; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.inventory.container.Container; import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.INBT; import net.minecraft.network.NetworkManager; import net.minecraft.network.play.server.SUpdateTileEntityPacket; import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TranslationTextComponent; import net.minecraftforge.fml.network.PacketDistributor; public class SoundPlayerTileEntity extends TileEntity implements INamedContainerProvider, ITickableTileEntity { private static final int MANUAL_CLICK_DEBOUNCE_TICKS = 6; private static final Map MANUAL_CLICK_GUARD = new ConcurrentHashMap(); private SoundSettings settings = new SoundSettings(); private ScenarioQueue scenario = new ScenarioQueue(); private boolean redstonePowered; private int timerTicks; private boolean playing; private int pendingStartTicks = -1; private boolean scenarioRunning; private int scenarioStepIndex; private int scenarioWaitTicks; private long lastPlayTick = Long.MIN_VALUE; private long lastStopTick = Long.MIN_VALUE; private boolean sourceEnabled = true; private boolean zoneEnabled = true; private boolean wizardCompleted; private ZoneShape zoneShape = ZoneShape.SPHERE; private float zoneRadius = 12.0f; private Vector3d zoneBoxHalfExtents = new Vector3d(8.0, 4.0, 8.0); private boolean zoneAutoStartOnEnter = true; private boolean zoneStopOnExit = true; private ZoneIntersectionPolicy zoneIntersectionPolicy = ZoneIntersectionPolicy.HIGHEST_PRIORITY; private ScenarioQueue zoneScenario = new ScenarioQueue(); private boolean zoneUseCustomCoords; private int zoneSourceX; private int zoneSourceY; private int zoneSourceZ; public SoundPlayerTileEntity() { super((TileEntityType)ModTileEntities.SOUND_PLAYER_TILE.get()); } public SoundSettings getSettings() { return this.settings; } public ScenarioQueue getScenario() { return this.scenario; } public boolean isSourceEnabled() { return this.sourceEnabled; } public boolean isZoneEnabled() { return this.zoneEnabled; } public boolean isWizardCompleted() { return this.wizardCompleted; } public ZoneShape getZoneShape() { return this.zoneShape; } public float getZoneRadius() { return this.zoneRadius; } public Vector3d getZoneBoxHalfExtents() { return this.zoneBoxHalfExtents; } public boolean isZoneAutoStartOnEnter() { return this.zoneAutoStartOnEnter; } public boolean isZoneStopOnExit() { return this.zoneStopOnExit; } public ZoneIntersectionPolicy getZoneIntersectionPolicy() { return this.zoneIntersectionPolicy; } public ScenarioQueue getZoneScenario() { return this.zoneScenario; } public boolean isZoneUseCustomCoords() { return this.zoneUseCustomCoords; } public int getZoneSourceX() { return this.zoneSourceX; } public int getZoneSourceY() { return this.zoneSourceY; } public int getZoneSourceZ() { return this.zoneSourceZ; } public BlockPos getZoneSourcePos() { if (this.zoneUseCustomCoords) { return new BlockPos(this.zoneSourceX, this.zoneSourceY, this.zoneSourceZ); } return this.worldPosition; } public void updateFromClient(CompoundNBT payload) { ActivationMode oldMode = this.settings.activationMode; this.settings = SoundSettings.fromNbt(payload.getCompound("settings")); this.scenario = ScenarioQueue.fromNbt(payload.getCompound("scenario")); this.sourceEnabled = payload.contains("sourceEnabled") ? payload.getBoolean("sourceEnabled") : this.sourceEnabled; this.zoneEnabled = payload.contains("zoneEnabled") ? payload.getBoolean("zoneEnabled") : this.zoneEnabled; this.wizardCompleted = payload.contains("wizardCompleted") ? payload.getBoolean("wizardCompleted") : this.wizardCompleted; this.zoneShape = this.parseZoneShape(payload.contains("zoneShape") ? payload.getString("zoneShape") : this.zoneShape.name()); this.zoneRadius = this.clampFloat(payload.contains("zoneRadius") ? payload.getFloat("zoneRadius") : this.zoneRadius, 1.0f, 256.0f); double boxX = payload.contains("zoneBoxX") ? payload.getDouble("zoneBoxX") : this.zoneBoxHalfExtents.x; double boxY = payload.contains("zoneBoxY") ? payload.getDouble("zoneBoxY") : this.zoneBoxHalfExtents.y; double boxZ = payload.contains("zoneBoxZ") ? payload.getDouble("zoneBoxZ") : this.zoneBoxHalfExtents.z; this.zoneBoxHalfExtents = new Vector3d(this.clampDouble(boxX, 0.5, 128.0), this.clampDouble(boxY, 0.5, 128.0), this.clampDouble(boxZ, 0.5, 128.0)); this.zoneAutoStartOnEnter = payload.contains("zoneAutoStartOnEnter") ? payload.getBoolean("zoneAutoStartOnEnter") : this.zoneAutoStartOnEnter; this.zoneStopOnExit = payload.contains("zoneStopOnExit") ? payload.getBoolean("zoneStopOnExit") : this.zoneStopOnExit; this.zoneIntersectionPolicy = this.parseZonePolicy(payload.contains("zoneIntersectionPolicy") ? payload.getString("zoneIntersectionPolicy") : this.zoneIntersectionPolicy.name()); if (payload.contains("zoneScenario")) { this.zoneScenario = ScenarioQueue.fromNbt(payload.getCompound("zoneScenario")); } this.zoneUseCustomCoords = payload.contains("zoneUseCustomCoords") ? payload.getBoolean("zoneUseCustomCoords") : this.zoneUseCustomCoords; this.zoneSourceX = payload.contains("zoneSourceX") ? payload.getInt("zoneSourceX") : this.zoneSourceX; this.zoneSourceY = payload.contains("zoneSourceY") ? payload.getInt("zoneSourceY") : this.zoneSourceY; int n = this.zoneSourceZ = payload.contains("zoneSourceZ") ? payload.getInt("zoneSourceZ") : this.zoneSourceZ; if (this.level != null && !this.level.isClientSide) { boolean powered = this.level.hasNeighborSignal(this.worldPosition); if (this.settings.activationMode == ActivationMode.REDSTONE) { if (oldMode != ActivationMode.REDSTONE) { this.redstonePowered = false; } this.onRedstoneChanged(powered); } else if (oldMode == ActivationMode.REDSTONE) { this.redstonePowered = powered; } } this.setChanged(); SoundDebug.log(SoundDebug.Level.L2, "TRIGGER", this.debugPosId(), "config updated soundId={} mode={} source={} zone={}", this.settings.soundId, this.settings.activationMode.name(), this.sourceEnabled, this.zoneEnabled); this.sync(); } public void onRedstoneChanged(boolean powered) { if (!this.sourceEnabled) { this.redstonePowered = powered; return; } if (this.settings.activationMode == ActivationMode.REDSTONE) { if (this.settings.redstoneMode == RedstoneMode.EDGE) { if (powered && !this.redstonePowered) { SoundDebug.log(SoundDebug.Level.L1, "TRIGGER", this.debugPosId(), "[REDSTONE] mode=EDGE event=rising action=play soundId={}", this.settings.soundId); this.play(); } else if (!powered && this.redstonePowered) { SoundDebug.log(SoundDebug.Level.L2, "TRIGGER", this.debugPosId(), "[REDSTONE] mode=EDGE event=falling action=none", new Object[0]); } } else if (powered && !this.redstonePowered) { SoundDebug.log(SoundDebug.Level.L1, "TRIGGER", this.debugPosId(), "[REDSTONE] mode=HOLD event=rising action=ensure_play soundId={}", this.settings.soundId); this.play(); } else if (powered && !this.isSourceRuntimeActive()) { SoundDebug.log(SoundDebug.Level.L2, "TRIGGER", this.debugPosId(), "[REDSTONE] mode=HOLD event=steady_high action=rearm_play soundId={}", this.settings.soundId); this.play(); } else if (!powered && this.redstonePowered && this.isSourceRuntimeActive()) { SoundDebug.log(SoundDebug.Level.L1, "TRIGGER", this.debugPosId(), "[REDSTONE] mode=HOLD event=falling action=stop", new Object[0]); this.stop(); } } this.redstonePowered = powered; } public void play() { if (!this.sourceEnabled) { return; } if (this.level != null && !this.level.isClientSide) { long now = this.level.getGameTime(); if (now == this.lastPlayTick) { SoundDebug.log(SoundDebug.Level.L3, "TRIGGER", this.debugPosId(), "play suppressed duplicate tick={}", now); return; } this.lastPlayTick = now; this.pendingStartTicks = Math.max(0, this.settings.startDelayTicks); if (!this.scenario.steps.isEmpty()) { this.scenarioRunning = true; this.scenarioStepIndex = 0; this.scenarioWaitTicks = this.pendingStartTicks; SoundDebug.log(SoundDebug.Level.L1, "TRIGGER", this.debugPosId(), "scenario start requested steps={} startDelay={}", this.scenario.steps.size(), this.pendingStartTicks); } else { this.scenarioRunning = false; SoundDebug.log(SoundDebug.Level.L1, "TRIGGER", this.debugPosId(), "play scheduled sourceId=sound_player:{} soundId={} startDelay={}", this.worldPosition.asLong(), this.settings.soundId, this.pendingStartTicks); } if (this.pendingStartTicks == 0 && !this.scenarioRunning) { this.emitPlayCurrentSettings(); this.pendingStartTicks = -1; } this.setChanged(); } } public void playFromClick(ServerPlayerEntity player) { if (this.level == null || this.level.isClientSide) { return; } long now = this.level.getGameTime(); String key = player.getUUID().toString() + ":" + this.worldPosition.asLong(); Long last = MANUAL_CLICK_GUARD.get(key); if (last != null && now - last < 6L) { SoundDebug.log(SoundDebug.Level.L3, "TRIGGER", this.debugPosId(), "click debounce suppress player={} dt={}", player.getScoreboardName(), now - last); return; } MANUAL_CLICK_GUARD.put(key, now); this.play(); } public void stop() { if (this.level != null && !this.level.isClientSide) { long now = this.level.getGameTime(); if (now == this.lastStopTick) { SoundDebug.log(SoundDebug.Level.L3, "TRIGGER", this.debugPosId(), "stop suppressed duplicate tick={}", now); return; } this.lastStopTick = now; this.playing = false; this.pendingStartTicks = -1; this.scenarioRunning = false; this.scenarioStepIndex = 0; this.scenarioWaitTicks = 0; SoundDebug.log(SoundDebug.Level.L2, "TRIGGER", this.debugPosId(), "stop requested sourceId=sound_player:{}", this.worldPosition.asLong()); NetworkHandler.CHANNEL.send(PacketDistributor.TRACKING_CHUNK.with(() -> this.level.getChunkAt(this.worldPosition)), (Object)new S2CBlockStateSyncPacket(this.worldPosition, this.save(new CompoundNBT()), false)); this.setChanged(); this.notifyNeighbors(); } } public boolean isPlaying() { return this.playing; } private void sync() { if (this.level != null && !this.level.isClientSide) { NetworkHandler.CHANNEL.send(PacketDistributor.TRACKING_CHUNK.with(() -> this.level.getChunkAt(this.worldPosition)), (Object)new S2CBlockStateSyncPacket(this.worldPosition, this.save(new CompoundNBT()), false)); NetworkHandler.CHANNEL.send(PacketDistributor.TRACKING_CHUNK.with(() -> this.level.getChunkAt(this.worldPosition)), (Object)new S2CZoneStateSyncPacket(this.worldPosition, this.createZoneSyncPayload())); } } public CompoundNBT createZoneSyncPayload() { CompoundNBT tag = new CompoundNBT(); tag.putBoolean("zoneEnabled", this.zoneEnabled); tag.putBoolean("sourceEnabled", this.sourceEnabled); tag.putBoolean("wizardCompleted", this.wizardCompleted); tag.putString("zoneShape", this.zoneShape.name()); tag.putFloat("zoneRadius", this.zoneRadius); tag.putDouble("zoneBoxX", this.zoneBoxHalfExtents.x); tag.putDouble("zoneBoxY", this.zoneBoxHalfExtents.y); tag.putDouble("zoneBoxZ", this.zoneBoxHalfExtents.z); tag.putBoolean("zoneAutoStartOnEnter", this.zoneAutoStartOnEnter); tag.putBoolean("zoneStopOnExit", this.zoneStopOnExit); tag.putString("zoneIntersectionPolicy", this.zoneIntersectionPolicy.name()); tag.put("zoneScenario", (INBT)this.zoneScenario.toNbt()); tag.putBoolean("zoneUseCustomCoords", this.zoneUseCustomCoords); tag.putInt("zoneSourceX", this.zoneSourceX); tag.putInt("zoneSourceY", this.zoneSourceY); tag.putInt("zoneSourceZ", this.zoneSourceZ); return tag; } public void loadZoneSyncPayload(CompoundNBT tag) { if (tag == null) { return; } if (tag.contains("zoneEnabled")) { this.zoneEnabled = tag.getBoolean("zoneEnabled"); } if (tag.contains("sourceEnabled")) { this.sourceEnabled = tag.getBoolean("sourceEnabled"); } if (tag.contains("wizardCompleted")) { this.wizardCompleted = tag.getBoolean("wizardCompleted"); } if (tag.contains("zoneShape")) { this.zoneShape = this.parseZoneShape(tag.getString("zoneShape")); } if (tag.contains("zoneRadius")) { this.zoneRadius = this.clampFloat(tag.getFloat("zoneRadius"), 1.0f, 256.0f); } double bx = tag.contains("zoneBoxX") ? tag.getDouble("zoneBoxX") : this.zoneBoxHalfExtents.x; double by = tag.contains("zoneBoxY") ? tag.getDouble("zoneBoxY") : this.zoneBoxHalfExtents.y; double bz = tag.contains("zoneBoxZ") ? tag.getDouble("zoneBoxZ") : this.zoneBoxHalfExtents.z; this.zoneBoxHalfExtents = new Vector3d(this.clampDouble(bx, 0.5, 128.0), this.clampDouble(by, 0.5, 128.0), this.clampDouble(bz, 0.5, 128.0)); if (tag.contains("zoneAutoStartOnEnter")) { this.zoneAutoStartOnEnter = tag.getBoolean("zoneAutoStartOnEnter"); } if (tag.contains("zoneStopOnExit")) { this.zoneStopOnExit = tag.getBoolean("zoneStopOnExit"); } if (tag.contains("zoneIntersectionPolicy")) { this.zoneIntersectionPolicy = this.parseZonePolicy(tag.getString("zoneIntersectionPolicy")); } if (tag.contains("zoneScenario")) { this.zoneScenario = ScenarioQueue.fromNbt(tag.getCompound("zoneScenario")); } if (tag.contains("zoneUseCustomCoords")) { this.zoneUseCustomCoords = tag.getBoolean("zoneUseCustomCoords"); } if (tag.contains("zoneSourceX")) { this.zoneSourceX = tag.getInt("zoneSourceX"); } if (tag.contains("zoneSourceY")) { this.zoneSourceY = tag.getInt("zoneSourceY"); } if (tag.contains("zoneSourceZ")) { this.zoneSourceZ = tag.getInt("zoneSourceZ"); } } public CompoundNBT save(CompoundNBT tag) { super.save(tag); tag.put("settings", (INBT)this.settings.toNbt()); tag.put("scenario", (INBT)this.scenario.toNbt()); tag.putBoolean("redstonePowered", this.redstonePowered); tag.putInt("timerTicks", this.timerTicks); tag.putBoolean("playing", this.playing); tag.putInt("pendingStartTicks", this.pendingStartTicks); tag.putBoolean("scenarioRunning", this.scenarioRunning); tag.putInt("scenarioStepIndex", this.scenarioStepIndex); tag.putInt("scenarioWaitTicks", this.scenarioWaitTicks); tag.putBoolean("sourceEnabled", this.sourceEnabled); tag.putBoolean("zoneEnabled", this.zoneEnabled); tag.putBoolean("wizardCompleted", this.wizardCompleted); tag.putString("zoneShape", this.zoneShape.name()); tag.putFloat("zoneRadius", this.zoneRadius); tag.putDouble("zoneBoxX", this.zoneBoxHalfExtents.x); tag.putDouble("zoneBoxY", this.zoneBoxHalfExtents.y); tag.putDouble("zoneBoxZ", this.zoneBoxHalfExtents.z); tag.putBoolean("zoneAutoStartOnEnter", this.zoneAutoStartOnEnter); tag.putBoolean("zoneStopOnExit", this.zoneStopOnExit); tag.putString("zoneIntersectionPolicy", this.zoneIntersectionPolicy.name()); tag.put("zoneScenario", (INBT)this.zoneScenario.toNbt()); tag.putBoolean("zoneUseCustomCoords", this.zoneUseCustomCoords); tag.putInt("zoneSourceX", this.zoneSourceX); tag.putInt("zoneSourceY", this.zoneSourceY); tag.putInt("zoneSourceZ", this.zoneSourceZ); return tag; } public void load(BlockState state, CompoundNBT tag) { super.load(state, tag); this.settings = SoundSettings.fromNbt(tag.getCompound("settings")); this.scenario = ScenarioQueue.fromNbt(tag.getCompound("scenario")); this.redstonePowered = tag.getBoolean("redstonePowered"); this.timerTicks = tag.getInt("timerTicks"); this.playing = tag.getBoolean("playing"); this.pendingStartTicks = tag.contains("pendingStartTicks") ? tag.getInt("pendingStartTicks") : -1; this.scenarioRunning = tag.getBoolean("scenarioRunning"); this.scenarioStepIndex = tag.getInt("scenarioStepIndex"); this.scenarioWaitTicks = tag.getInt("scenarioWaitTicks"); this.sourceEnabled = tag.contains("sourceEnabled") ? tag.getBoolean("sourceEnabled") : true; this.zoneEnabled = tag.contains("zoneEnabled") ? tag.getBoolean("zoneEnabled") : true; this.wizardCompleted = tag.getBoolean("wizardCompleted"); this.zoneShape = this.parseZoneShape(tag.contains("zoneShape") ? tag.getString("zoneShape") : ZoneShape.SPHERE.name()); this.zoneRadius = this.clampFloat(tag.contains("zoneRadius") ? tag.getFloat("zoneRadius") : 12.0f, 1.0f, 256.0f); this.zoneBoxHalfExtents = new Vector3d(this.clampDouble(tag.contains("zoneBoxX") ? tag.getDouble("zoneBoxX") : 8.0, 0.5, 128.0), this.clampDouble(tag.contains("zoneBoxY") ? tag.getDouble("zoneBoxY") : 4.0, 0.5, 128.0), this.clampDouble(tag.contains("zoneBoxZ") ? tag.getDouble("zoneBoxZ") : 8.0, 0.5, 128.0)); this.zoneAutoStartOnEnter = tag.contains("zoneAutoStartOnEnter") ? tag.getBoolean("zoneAutoStartOnEnter") : true; this.zoneStopOnExit = tag.contains("zoneStopOnExit") ? tag.getBoolean("zoneStopOnExit") : true; this.zoneIntersectionPolicy = this.parseZonePolicy(tag.contains("zoneIntersectionPolicy") ? tag.getString("zoneIntersectionPolicy") : ZoneIntersectionPolicy.HIGHEST_PRIORITY.name()); this.zoneScenario = tag.contains("zoneScenario") ? ScenarioQueue.fromNbt(tag.getCompound("zoneScenario")) : new ScenarioQueue(); this.zoneUseCustomCoords = tag.contains("zoneUseCustomCoords") && tag.getBoolean("zoneUseCustomCoords"); this.zoneSourceX = tag.contains("zoneSourceX") ? tag.getInt("zoneSourceX") : this.worldPosition.getX(); this.zoneSourceY = tag.contains("zoneSourceY") ? tag.getInt("zoneSourceY") : this.worldPosition.getY(); this.zoneSourceZ = tag.contains("zoneSourceZ") ? tag.getInt("zoneSourceZ") : this.worldPosition.getZ(); } public SUpdateTileEntityPacket getUpdatePacket() { return new SUpdateTileEntityPacket(this.worldPosition, 0, this.getUpdateTag()); } public CompoundNBT getUpdateTag() { return this.save(new CompoundNBT()); } public void onDataPacket(NetworkManager net, SUpdateTileEntityPacket pkt) { this.load(this.getBlockState(), pkt.getTag()); } public ITextComponent getDisplayName() { return new TranslationTextComponent("screen.soundmod.sound_player"); } @Nullable public Container createMenu(int windowId, PlayerInventory playerInventory, PlayerEntity player) { return new SoundPlayerContainer(windowId, this.level, this.worldPosition, playerInventory, player); } public void tick() { if (this.level == null || this.level.isClientSide) { return; } if (!this.sourceEnabled) { if (this.playing) { this.stop(); } return; } if (this.settings.activationMode == ActivationMode.REDSTONE) { boolean poweredNow = this.level.hasNeighborSignal(this.worldPosition); if (poweredNow != this.redstonePowered) { this.onRedstoneChanged(poweredNow); } else if (this.settings.redstoneMode == RedstoneMode.HOLD && poweredNow && !this.isSourceRuntimeActive()) { SoundDebug.log(SoundDebug.Level.L3, "TRIGGER", this.debugPosId(), "[REDSTONE] mode=HOLD event=tick_guard action=ensure_play", new Object[0]); this.play(); } } if (this.settings.activationMode == ActivationMode.AUTO && !this.playing) { SoundDebug.log(SoundDebug.Level.L2, "TRIGGER", this.debugPosId(), "auto mode trigger", new Object[0]); this.play(); } if (this.settings.activationMode == ActivationMode.TIMER) { ++this.timerTicks; int interval = Math.max(20, this.settings.repeatDelayTicks <= 0 ? 20 : this.settings.repeatDelayTicks); if (this.timerTicks >= interval) { this.timerTicks = 0; SoundDebug.log(SoundDebug.Level.L2, "TRIGGER", this.debugPosId(), "timer trigger interval={}", interval); this.play(); } } if (this.pendingStartTicks >= 0 && !this.scenarioRunning) { if (this.pendingStartTicks == 0) { this.emitPlayCurrentSettings(); this.pendingStartTicks = -1; this.setChanged(); } else { --this.pendingStartTicks; } } if (this.scenarioRunning) { this.tickScenario(); } } private void tickScenario() { if (this.scenario.steps.isEmpty()) { this.scenarioRunning = false; return; } if (this.scenarioWaitTicks > 0) { --this.scenarioWaitTicks; return; } if (this.scenario.shuffle) { int size = this.scenario.steps.size(); int nextIdx = 0; if (size > 1) { do { nextIdx = this.level.random.nextInt(size); } while (nextIdx == this.scenarioStepIndex && this.level.random.nextFloat() > 0.15f); } this.scenarioStepIndex = nextIdx; ScenarioQueue.Step step = this.scenario.steps.get(nextIdx); this.scenarioWaitTicks = Math.max(0, step.delayTicks); this.emitScenarioStepPlay(step.soundId); this.setChanged(); return; } if (this.scenarioStepIndex >= this.scenario.steps.size()) { if (this.scenario.loop) { this.scenarioStepIndex = 0; } else { this.scenarioRunning = false; return; } } ScenarioQueue.Step step = this.scenario.steps.get(this.scenarioStepIndex); ++this.scenarioStepIndex; this.scenarioWaitTicks = Math.max(0, step.delayTicks); this.emitScenarioStepPlay(step.soundId); this.setChanged(); } private void emitPlayCurrentSettings() { this.playing = true; SoundDebug.log(SoundDebug.Level.L1, "TRIGGER", this.debugPosId(), "play requested sourceId=sound_player:{} soundId={}", this.worldPosition.asLong(), this.settings.soundId); NetworkHandler.CHANNEL.send(PacketDistributor.TRACKING_CHUNK.with(() -> this.level.getChunkAt(this.worldPosition)), (Object)new S2CBlockStateSyncPacket(this.worldPosition, this.save(new CompoundNBT()), true)); this.notifyNeighbors(); } private void emitScenarioStepPlay(String soundId) { SoundSettings stepSettings = SoundSettings.sanitizedCopy(this.settings); stepSettings.soundId = soundId; this.playing = true; SoundDebug.log(SoundDebug.Level.L1, "TRIGGER", this.debugPosId(), "scenario step play sourceId=sound_player:{} stepSoundId={} nextDelay={}", this.worldPosition.asLong(), soundId, this.scenarioWaitTicks); NetworkHandler.CHANNEL.send(PacketDistributor.TRACKING_CHUNK.with(() -> this.level.getChunkAt(this.worldPosition)), (Object)new S2CPlaySoundPacket("sound_player:" + this.worldPosition.asLong(), this.worldPosition, stepSettings)); this.notifyNeighbors(); } public int getScenarioStepIndex() { return this.scenarioStepIndex; } private void notifyNeighbors() { if (this.level != null && !this.level.isClientSide) { this.level.updateNeighborsAt(this.worldPosition, this.getBlockState().getBlock()); } } private boolean isSourceRuntimeActive() { return this.playing || this.pendingStartTicks >= 0 || this.scenarioRunning; } private String debugPosId() { return this.worldPosition.getX() + "," + this.worldPosition.getY() + "," + this.worldPosition.getZ(); } private ZoneShape parseZoneShape(String raw) { try { return ZoneShape.valueOf(raw); } catch (Exception ignored) { return ZoneShape.SPHERE; } } private ZoneIntersectionPolicy parseZonePolicy(String raw) { try { return ZoneIntersectionPolicy.valueOf(raw); } catch (Exception ignored) { return ZoneIntersectionPolicy.HIGHEST_PRIORITY; } } private float clampFloat(float value, float min, float max) { return Math.max(min, Math.min(max, value)); } private double clampDouble(double value, double min, double max) { return Math.max(min, Math.min(max, value)); } }