hytale-server/com/hypixel/hytale/server/npc/instructions/builders/BuilderInstructionRandomize...

195 lines
7.2 KiB
Java

package com.hypixel.hytale.server.npc.instructions.builders;
import com.google.gson.JsonElement;
import com.hypixel.hytale.server.npc.asset.builder.Builder;
import com.hypixel.hytale.server.npc.asset.builder.BuilderDescriptorState;
import com.hypixel.hytale.server.npc.asset.builder.BuilderSupport;
import com.hypixel.hytale.server.npc.asset.builder.BuilderValidationHelper;
import com.hypixel.hytale.server.npc.asset.builder.FeatureEvaluatorHelper;
import com.hypixel.hytale.server.npc.asset.builder.holder.BooleanHolder;
import com.hypixel.hytale.server.npc.asset.builder.holder.NumberArrayHolder;
import com.hypixel.hytale.server.npc.asset.builder.validators.DoubleSequenceValidator;
import com.hypixel.hytale.server.npc.asset.builder.validators.DoubleSingleValidator;
import com.hypixel.hytale.server.npc.asset.builder.validators.StringNullOrNotEmptyValidator;
import com.hypixel.hytale.server.npc.instructions.Instruction;
import com.hypixel.hytale.server.npc.instructions.InstructionRandomized;
import com.hypixel.hytale.server.npc.instructions.Sensor;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class BuilderInstructionRandomized extends BuilderInstruction {
public static final double[] DEFAULT_EXECUTION_RANGE = new double[]{Double.MAX_VALUE, Double.MAX_VALUE};
protected final BooleanHolder resetOnStateChange = new BooleanHolder();
protected final NumberArrayHolder executeFor = new NumberArrayHolder();
@Nonnull
@Override
public String getShortDescription() {
return "Randomised list of weighted instructions.";
}
@Nonnull
@Override
public String getLongDescription() {
return "Randomised list of weighted instructions. One will be selected at random and executed until the NPC state changes.";
}
@Nullable
public InstructionRandomized build(@Nonnull BuilderSupport builderSupport) {
if (!this.enabled.get(builderSupport.getExecutionContext())) {
return null;
} else {
Sensor sensor;
if (this.sensorBuilderObjectReferenceHelper.isPresent()) {
sensor = this.getSensor(builderSupport);
if (sensor == null) {
return null;
}
} else {
sensor = Sensor.NULL;
}
if (this.currentStateName != null) {
builderSupport.pushCurrentStateName(this.currentStateName);
}
Instruction[] instructionList = this.hasNestedInstructions() ? this.getSteps(builderSupport) : null;
if (instructionList == null) {
if (this.currentStateName != null) {
builderSupport.popCurrentStateName();
}
return null;
} else {
if (this.currentStateName != null) {
builderSupport.popCurrentStateName();
}
return new InstructionRandomized(this, sensor, instructionList, builderSupport);
}
}
}
@Nonnull
@Override
public Builder<Instruction> readConfig(@Nonnull JsonElement data) {
FeatureEvaluatorHelper features = new FeatureEvaluatorHelper();
BuilderValidationHelper helper = new BuilderValidationHelper(
this.fileName,
features,
this.internalReferenceResolver,
this.stateHelper,
this.instructionContextHelper,
this.extraInfo,
this.evaluators,
this.readErrors
);
this.increaseDepth();
if (this.requiresName()) {
this.requireString(data, "Name", v -> this.name = v, null, BuilderDescriptorState.Stable, "Name for referencing", null);
} else {
this.getString(data, "Name", v -> this.name = v, null, null, BuilderDescriptorState.Stable, "Optional name for descriptor", null);
}
this.getString(
data,
"Tag",
v -> this.tag = v,
null,
StringNullOrNotEmptyValidator.get(),
BuilderDescriptorState.Experimental,
"Internal identifier tag for debugging",
null
);
this.getBoolean(data, "Enabled", this.enabled, true, BuilderDescriptorState.Stable, "Whether this step should be enabled on the NPC", null);
this.getObject(
data,
"Sensor",
this.sensorBuilderObjectReferenceHelper,
BuilderDescriptorState.Stable,
"Sensor for testing if step can be applied",
"Sensor for testing if step can be applied. If not supplied, will always match",
helper
);
features.lock();
this.getArray(
data,
"Instructions",
this.steps,
null,
BuilderDescriptorState.Stable,
"List of weighted instructions to select from",
null,
new BuilderValidationHelper(
this.fileName,
null,
this.internalReferenceResolver,
this.stateHelper,
this.instructionContextHelper,
this.extraInfo,
this.evaluators,
this.readErrors
)
);
this.getBoolean(
data, "Continue", v -> this.continueAfter = v, false, BuilderDescriptorState.WorkInProgress, "Continue after this step was executed", null
);
this.getDouble(
data,
"Weight",
this.chance,
1.0,
DoubleSingleValidator.greater0(),
BuilderDescriptorState.Stable,
"Weighted chance of picking this step in a random selector",
null
);
this.getBoolean(
data,
"TreeMode",
v -> this.treeMode = v,
false,
BuilderDescriptorState.Stable,
"Whether this step and its contents should be treated like a traditional behaviour tree.",
"Whether this step and its contents should be treated like a traditional behaviour tree, i.e. will continue if all child steps fail"
);
this.getBoolean(
data,
"InvertTreeModeResult",
this.invertTreeModeResult,
false,
BuilderDescriptorState.Stable,
"Whether or not to invert the result of TreeMode evaluation when passing up to parent TreeMode steps",
null
);
this.getBoolean(data, "ResetOnStateChange", this.resetOnStateChange, true, BuilderDescriptorState.Stable, "Whether to reset when NPC state changes", null);
this.getDoubleRange(
data,
"ExecuteFor",
this.executeFor,
DEFAULT_EXECUTION_RANGE,
DoubleSequenceValidator.fromExclToInclWeaklyMonotonic(0.0, Double.MAX_VALUE),
BuilderDescriptorState.Stable,
"How long to execute the chosen step before picking another",
null
);
this.decreaseDepth();
this.validateBooleanImplicationAnyAntecedent(ANTECEDENT, new boolean[]{this.treeMode}, true, SUBSEQUENT, new boolean[]{this.continueAfter}, false);
return this;
}
@Nonnull
@Override
public BuilderDescriptorState getBuilderDescriptorState() {
return BuilderDescriptorState.Stable;
}
public boolean getResetOnStateChange(@Nonnull BuilderSupport support) {
return this.resetOnStateChange.get(support.getExecutionContext());
}
public double[] getExecuteFor(@Nonnull BuilderSupport support) {
return this.executeFor.get(support.getExecutionContext());
}
}