package com.hypixel.hytale.builtin.buildertools.scriptedbrushes.operations.sequential;
import com.hypixel.hytale.builtin.buildertools.scriptedbrushes.BrushConfig;
import com.hypixel.hytale.builtin.buildertools.scriptedbrushes.BrushConfigCommandExecutor;
import com.hypixel.hytale.builtin.buildertools.scriptedbrushes.operations.sequential.flowcontrol.JumpIfCompareOperation;
import com.hypixel.hytale.builtin.buildertools.scriptedbrushes.operations.system.SequenceBrushOperation;
import com.hypixel.hytale.codec.Codec;
import com.hypixel.hytale.codec.KeyedCodec;
import com.hypixel.hytale.codec.builder.BuilderCodec;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class BreakpointOperation extends SequenceBrushOperation {
private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass();
public static final BuilderCodec<BreakpointOperation> CODEC;
@Nonnull
private String label = "";
@Nonnull
private Boolean printMessage = false;
@Nonnull
private Boolean printState = false;
@Nonnull
private Boolean enterStepMode = false;
@Nullable
private JumpIfCompareOperation.BrushConfigIntegerComparison condition = null;
public BreakpointOperation() {
super("Breakpoint", "Debug breakpoint for scripted brushes", false);
}
public void modifyBrushConfig(@Nonnull Ref<EntityStore> ref, @Nonnull BrushConfig brushConfig, @Nonnull BrushConfigCommandExecutor executor, @Nonnull ComponentAccessor<EntityStore> componentAccessor) {
if (executor.isEnableBreakpoints()) {
if (this.condition == null || this.condition.apply(brushConfig)) {
int currentIndex = executor.getCurrentOperationIndex();
BrushConfigCommandExecutor.DebugOutputTarget outputTarget = executor.getDebugOutputTarget();
PlayerRef playerRefComponent = (PlayerRef)componentAccessor.getComponent(ref, PlayerRef.getComponentType());
String labelDisplay = this.label.isEmpty() ? "unnamed" : this.label;
boolean hasAnyOutput = this.printMessage || this.printState || this.enterStepMode;
if (hasAnyOutput) {
if (this.shouldSendToChat(outputTarget) && playerRefComponent != null) {
playerRefComponent.sendMessage(Message.translation("server.builderTools.brushConfig.debug.breakpointReached").param("label", labelDisplay).param("index", currentIndex));
}
if (this.shouldSendToConsole(outputTarget)) {
LOGGER.at(Level.INFO).log("[Breakpoint] '%s' reached at operation #%d", labelDisplay, currentIndex);
}
}
if (this.printState) {
String stateInfo = brushConfig.getInfo();
if (this.shouldSendToChat(outputTarget) && playerRefComponent != null) {
playerRefComponent.sendMessage(Message.translation("server.builderTools.brushConfig.debug.breakpointState").param("index", currentIndex).param("state", stateInfo));
}
if (this.shouldSendToConsole(outputTarget)) {
LOGGER.at(Level.INFO).log("[Breakpoint] [Operation #%d] %s", currentIndex, stateInfo);
}
}
if (this.enterStepMode) {
if (this.shouldSendToChat(outputTarget) && playerRefComponent != null) {
playerRefComponent.sendMessage(Message.translation("server.builderTools.brushConfig.debug.breakpointEnteringStepMode").param("label", labelDisplay));
}
if (this.shouldSendToConsole(outputTarget)) {
LOGGER.at(Level.INFO).log("[Breakpoint] '%s' - Entering step-through mode", labelDisplay);
}
executor.setInDebugSteppingMode(true);
}
}
}
}
private boolean shouldSendToChat(BrushConfigCommandExecutor.DebugOutputTarget target) {
return target == BrushConfigCommandExecutor.DebugOutputTarget.Chat || target == BrushConfigCommandExecutor.DebugOutputTarget.Both;
}
private boolean shouldSendToConsole(BrushConfigCommandExecutor.DebugOutputTarget target) {
return target == BrushConfigCommandExecutor.DebugOutputTarget.Console || target == BrushConfigCommandExecutor.DebugOutputTarget.Both;
}
static {
CODEC = ((BuilderCodec.Builder)((BuilderCodec.Builder)((BuilderCodec.Builder)((BuilderCodec.Builder)((BuilderCodec.Builder)((BuilderCodec.Builder)BuilderCodec.builder(BreakpointOperation.class, BreakpointOperation::new).append(new KeyedCodec("Label", Codec.STRING), (op, val) -> op.label = val, (op) -> op.label).documentation("Identifier for this breakpoint").add()).append(new KeyedCodec("PrintMessage", Codec.BOOLEAN), (op, val) -> op.printMessage = val, (op) -> op.printMessage).documentation("Print a message when breakpoint is reached").add()).append(new KeyedCodec("PrintState", Codec.BOOLEAN), (op, val) -> op.printState = val, (op) -> op.printState).documentation("Print brush state when breakpoint is reached").add()).append(new KeyedCodec("EnterStepMode", Codec.BOOLEAN), (op, val) -> op.enterStepMode = val, (op) -> op.enterStepMode).documentation("Enter step-through mode (use /sb step to continue)").add()).append(new KeyedCodec("Condition", JumpIfCompareOperation.BrushConfigIntegerComparison.CODEC), (op, val) -> op.condition = val, (op) -> op.condition).documentation("Optional condition - breakpoint only triggers if condition passes").add()).documentation("Debug breakpoint for scripted brushes")).build();
}
}