604 lines
28 KiB
Java
604 lines
28 KiB
Java
/*
|
|
* 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<String, Long> MANUAL_CLICK_GUARD = new ConcurrentHashMap<String, Long>();
|
|
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));
|
|
}
|
|
}
|
|
|